StackWalker.cpp 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233
  1. /**********************************************************************
  2. *
  3. * StackWalker.cpp
  4. * http://stackwalker.codeplex.com/
  5. *
  6. *
  7. * History:
  8. * 2005-07-27 v1 - First public release on http://www.codeproject.com/
  9. * http://www.codeproject.com/threads/StackWalker.asp
  10. * 2005-07-28 v2 - Changed the params of the constructor and ShowCallstack
  11. * (to simplify the usage)
  12. * 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL
  13. * (should also be enough)
  14. * - Changed to compile correctly with the PSDK of VC7.0
  15. * (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined:
  16. * it uses LPSTR instead of LPCSTR as first paremeter)
  17. * - Added declarations to support VC5/6 without using 'dbghelp.h'
  18. * - Added a 'pUserData' member to the ShowCallstack function and the
  19. * PReadProcessMemoryRoutine declaration (to pass some user-defined data,
  20. * which can be used in the readMemoryFunction-callback)
  21. * 2005-08-02 v4 - OnSymInit now also outputs the OS-Version by default
  22. * - Added example for doing an exception-callstack-walking in main.cpp
  23. * (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268)
  24. * 2005-08-05 v5 - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse!
  25. * 2008-08-04 v6 - Fixed Bug: Missing LEAK-end-tag
  26. * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2502890#xx2502890xx
  27. * Fixed Bug: Compiled with "WIN32_LEAN_AND_MEAN"
  28. * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=1824718#xx1824718xx
  29. * Fixed Bug: Compiling with "/Wall"
  30. * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2638243#xx2638243xx
  31. * Fixed Bug: Now checking SymUseSymSrv
  32. * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1388979#xx1388979xx
  33. * Fixed Bug: Support for recursive function calls
  34. * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1434538#xx1434538xx
  35. * Fixed Bug: Missing FreeLibrary call in "GetModuleListTH32"
  36. * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1326923#xx1326923xx
  37. * Fixed Bug: SymDia is number 7, not 9!
  38. * 2008-09-11 v7 For some (undocumented) reason, dbhelp.h is needing a packing of 8!
  39. * Thanks to Teajay which reported the bug...
  40. * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2718933#xx2718933xx
  41. * 2008-11-27 v8 Debugging Tools for Windows are now stored in a different directory
  42. * Thanks to Luiz Salamon which reported this "bug"...
  43. * http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2822736#xx2822736xx
  44. * 2009-04-10 v9 License slihtly corrected (<ORGANIZATION> replaced)
  45. * 2009-11-01 v10 Moved to http://stackwalker.codeplex.com/
  46. * 2009-11-02 v11 Now try to use IMAGEHLP_MODULE64_V3 if available
  47. * 2010-04-15 v12 Added support for VS2010 RTM
  48. * 2010-05-25 v13 Now using secure MyStrcCpy. Thanks to luke.simon:
  49. * http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=3477467#xx3477467xx
  50. * 2013-01-07 v14 Runtime Check Error VS2010 Debug Builds fixed:
  51. * http://stackwalker.codeplex.com/workitem/10511
  52. *
  53. * LICENSE (http://www.opensource.org/licenses/bsd-license.php)
  54. *
  55. * Copyright (c) 2005-2011, Jochen Kalmbach
  56. * All rights reserved.
  57. *
  58. * Redistribution and use in source and binary forms, with or without modification,
  59. * are permitted provided that the following conditions are met:
  60. *
  61. * Redistributions of source code must retain the above copyright notice,
  62. * this list of conditions and the following disclaimer.
  63. * Redistributions in binary form must reproduce the above copyright notice,
  64. * this list of conditions and the following disclaimer in the documentation
  65. * and/or other materials provided with the distribution.
  66. * Neither the name of Jochen Kalmbach nor the names of its contributors may be
  67. * used to endorse or promote products derived from this software without
  68. * specific prior written permission.
  69. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  70. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  71. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  72. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
  73. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  74. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  75. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  76. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  77. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  78. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  79. *
  80. **********************************************************************/
  81. #include <windows.h>
  82. #include <tchar.h>
  83. #include <stdio.h>
  84. #include <stdlib.h>
  85. #pragma comment(lib, "version.lib") // for "VerQueryValue"
  86. #pragma warning(disable:4826)
  87. #pragma warning(disable:4748)
  88. #include "StackWalker.h"
  89. // Some missing defines (for VC5/6):
  90. #ifndef INVALID_FILE_ATTRIBUTES
  91. #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
  92. #endif
  93. // secure-CRT_functions are only available starting with VC8
  94. #if _MSC_VER < 1400
  95. #define strcpy_s(dst, len, src) strcpy(dst, src)
  96. #define strncpy_s(dst, len, src, maxLen) strncpy(dst, len, src)
  97. #define strcat_s(dst, len, src) strcat(dst, src)
  98. #define _snprintf_s _snprintf
  99. #define _tcscat_s _tcscat
  100. #endif
  101. static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc)
  102. {
  103. if (nMaxDestSize <= 0) return;
  104. if (strlen(szSrc) < nMaxDestSize)
  105. {
  106. strcpy_s(szDest, nMaxDestSize, szSrc);
  107. }
  108. else
  109. {
  110. strncpy_s(szDest, nMaxDestSize, szSrc, nMaxDestSize);
  111. szDest[nMaxDestSize-1] = 0;
  112. }
  113. } // MyStrCpy
  114. // Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL')
  115. #define USED_CONTEXT_FLAGS CONTEXT_FULL
  116. class StackWalkerInternal
  117. {
  118. public:
  119. StackWalkerInternal(StackWalker *parent, HANDLE hProcess)
  120. {
  121. m_parent = parent;
  122. m_hDbhHelp = NULL;
  123. pSC = NULL;
  124. m_hProcess = hProcess;
  125. m_szSymPath = NULL;
  126. pSFTA = NULL;
  127. pSGLFA = NULL;
  128. pSGMB = NULL;
  129. pSGMI = NULL;
  130. pSGO = NULL;
  131. pSGSFA = NULL;
  132. pSI = NULL;
  133. pSLM = NULL;
  134. pSSO = NULL;
  135. pSW = NULL;
  136. pUDSN = NULL;
  137. pSGSP = NULL;
  138. }
  139. ~StackWalkerInternal()
  140. {
  141. if (pSC != NULL)
  142. pSC(m_hProcess); // SymCleanup
  143. if (m_hDbhHelp != NULL)
  144. FreeLibrary(m_hDbhHelp);
  145. m_hDbhHelp = NULL;
  146. m_parent = NULL;
  147. if(m_szSymPath != NULL)
  148. free(m_szSymPath);
  149. m_szSymPath = NULL;
  150. }
  151. BOOL Init(LPCSTR szSymPath)
  152. {
  153. if (m_parent == NULL)
  154. return FALSE;
  155. // Dynamically load the Entry-Points for dbghelp.dll:
  156. // First try to load the newsest one from
  157. TCHAR szTemp[4096];
  158. // But before wqe do this, we first check if the ".local" file exists
  159. if (GetModuleFileName(NULL, szTemp, 4096) > 0)
  160. {
  161. _tcscat_s(szTemp, _T(".local"));
  162. if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES)
  163. {
  164. // ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows"
  165. // Ok, first try the new path according to the archtitecture:
  166. #ifdef _M_IX86
  167. if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) )
  168. {
  169. _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x86)\\dbghelp.dll"));
  170. // now check if the file exists:
  171. if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
  172. {
  173. m_hDbhHelp = LoadLibrary(szTemp);
  174. }
  175. }
  176. #elif _M_X64
  177. if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) )
  178. {
  179. _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x64)\\dbghelp.dll"));
  180. // now check if the file exists:
  181. if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
  182. {
  183. m_hDbhHelp = LoadLibrary(szTemp);
  184. }
  185. }
  186. #elif _M_IA64
  187. if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) )
  188. {
  189. _tcscat_s(szTemp, _T("\\Debugging Tools for Windows (ia64)\\dbghelp.dll"));
  190. // now check if the file exists:
  191. if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
  192. {
  193. m_hDbhHelp = LoadLibrary(szTemp);
  194. }
  195. }
  196. #endif
  197. // If still not found, try the old directories...
  198. if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) )
  199. {
  200. _tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll"));
  201. // now check if the file exists:
  202. if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
  203. {
  204. m_hDbhHelp = LoadLibrary(szTemp);
  205. }
  206. }
  207. #if defined _M_X64 || defined _M_IA64
  208. // Still not found? Then try to load the (old) 64-Bit version:
  209. if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) )
  210. {
  211. _tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll"));
  212. if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
  213. {
  214. m_hDbhHelp = LoadLibrary(szTemp);
  215. }
  216. }
  217. #endif
  218. }
  219. }
  220. if (m_hDbhHelp == NULL) // if not already loaded, try to load a default-one
  221. m_hDbhHelp = LoadLibrary( _T("dbghelp.dll") );
  222. if (m_hDbhHelp == NULL)
  223. return FALSE;
  224. pSI = (tSI) GetProcAddress(m_hDbhHelp, "SymInitialize" );
  225. pSC = (tSC) GetProcAddress(m_hDbhHelp, "SymCleanup" );
  226. pSW = (tSW) GetProcAddress(m_hDbhHelp, "StackWalk64" );
  227. pSGO = (tSGO) GetProcAddress(m_hDbhHelp, "SymGetOptions" );
  228. pSSO = (tSSO) GetProcAddress(m_hDbhHelp, "SymSetOptions" );
  229. pSFTA = (tSFTA) GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64" );
  230. pSGLFA = (tSGLFA) GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64" );
  231. pSGMB = (tSGMB) GetProcAddress(m_hDbhHelp, "SymGetModuleBase64" );
  232. pSGMI = (tSGMI) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" );
  233. pSGSFA = (tSGSFA) GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64" );
  234. pUDSN = (tUDSN) GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName" );
  235. pSLM = (tSLM) GetProcAddress(m_hDbhHelp, "SymLoadModule64" );
  236. pSGSP =(tSGSP) GetProcAddress(m_hDbhHelp, "SymGetSearchPath" );
  237. if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL ||
  238. pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL ||
  239. pSW == NULL || pUDSN == NULL || pSLM == NULL )
  240. {
  241. FreeLibrary(m_hDbhHelp);
  242. m_hDbhHelp = NULL;
  243. pSC = NULL;
  244. return FALSE;
  245. }
  246. // SymInitialize
  247. if (szSymPath != NULL)
  248. m_szSymPath = _strdup(szSymPath);
  249. if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE)
  250. this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0);
  251. DWORD symOptions = this->pSGO(); // SymGetOptions
  252. symOptions |= SYMOPT_LOAD_LINES;
  253. symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;
  254. //symOptions |= SYMOPT_NO_PROMPTS;
  255. // SymSetOptions
  256. symOptions = this->pSSO(symOptions);
  257. char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0};
  258. if (this->pSGSP != NULL)
  259. {
  260. if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE)
  261. this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0);
  262. }
  263. char szUserName[1024] = {0};
  264. DWORD dwSize = 1024;
  265. GetUserNameA(szUserName, &dwSize);
  266. this->m_parent->OnSymInit(buf, symOptions, szUserName);
  267. return TRUE;
  268. }
  269. StackWalker *m_parent;
  270. HMODULE m_hDbhHelp;
  271. HANDLE m_hProcess;
  272. LPSTR m_szSymPath;
  273. #pragma pack(push,8)
  274. struct IMAGEHLP_MODULE64_V3 {
  275. DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
  276. DWORD64 BaseOfImage; // base load address of module
  277. DWORD ImageSize; // virtual size of the loaded module
  278. DWORD TimeDateStamp; // date/time stamp from pe header
  279. DWORD CheckSum; // checksum from the pe header
  280. DWORD NumSyms; // number of symbols in the symbol table
  281. SYM_TYPE SymType; // type of symbols loaded
  282. CHAR ModuleName[32]; // module name
  283. CHAR ImageName[256]; // image name
  284. CHAR LoadedImageName[256]; // symbol file name
  285. // new elements: 07-Jun-2002
  286. CHAR LoadedPdbName[256]; // pdb file name
  287. DWORD CVSig; // Signature of the CV record in the debug directories
  288. CHAR CVData[MAX_PATH * 3]; // Contents of the CV record
  289. DWORD PdbSig; // Signature of PDB
  290. GUID PdbSig70; // Signature of PDB (VC 7 and up)
  291. DWORD PdbAge; // DBI age of pdb
  292. BOOL PdbUnmatched; // loaded an unmatched pdb
  293. BOOL DbgUnmatched; // loaded an unmatched dbg
  294. BOOL LineNumbers; // we have line number information
  295. BOOL GlobalSymbols; // we have internal symbol information
  296. BOOL TypeInfo; // we have type information
  297. // new elements: 17-Dec-2003
  298. BOOL SourceIndexed; // pdb supports source server
  299. BOOL Publics; // contains public symbols
  300. };
  301. struct IMAGEHLP_MODULE64_V2 {
  302. DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
  303. DWORD64 BaseOfImage; // base load address of module
  304. DWORD ImageSize; // virtual size of the loaded module
  305. DWORD TimeDateStamp; // date/time stamp from pe header
  306. DWORD CheckSum; // checksum from the pe header
  307. DWORD NumSyms; // number of symbols in the symbol table
  308. SYM_TYPE SymType; // type of symbols loaded
  309. CHAR ModuleName[32]; // module name
  310. CHAR ImageName[256]; // image name
  311. CHAR LoadedImageName[256]; // symbol file name
  312. };
  313. #pragma pack(pop)
  314. // SymCleanup()
  315. typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess );
  316. tSC pSC;
  317. // SymFunctionTableAccess64()
  318. typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD64 AddrBase );
  319. tSFTA pSFTA;
  320. // SymGetLineFromAddr64()
  321. typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,
  322. OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line );
  323. tSGLFA pSGLFA;
  324. // SymGetModuleBase64()
  325. typedef DWORD64 (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD64 dwAddr );
  326. tSGMB pSGMB;
  327. // SymGetModuleInfo64()
  328. typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V3 *ModuleInfo );
  329. tSGMI pSGMI;
  330. // SymGetOptions()
  331. typedef DWORD (__stdcall *tSGO)( VOID );
  332. tSGO pSGO;
  333. // SymGetSymFromAddr64()
  334. typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,
  335. OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol );
  336. tSGSFA pSGSFA;
  337. // SymInitialize()
  338. typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess );
  339. tSI pSI;
  340. // SymLoadModule64()
  341. typedef DWORD64 (__stdcall *tSLM)( IN HANDLE hProcess, IN HANDLE hFile,
  342. IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll );
  343. tSLM pSLM;
  344. // SymSetOptions()
  345. typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions );
  346. tSSO pSSO;
  347. // StackWalk64()
  348. typedef BOOL (__stdcall *tSW)(
  349. DWORD MachineType,
  350. HANDLE hProcess,
  351. HANDLE hThread,
  352. LPSTACKFRAME64 StackFrame,
  353. PVOID ContextRecord,
  354. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
  355. PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
  356. PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
  357. PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress );
  358. tSW pSW;
  359. // UnDecorateSymbolName()
  360. typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName,
  361. DWORD UndecoratedLength, DWORD Flags );
  362. tUDSN pUDSN;
  363. typedef BOOL (__stdcall WINAPI *tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength);
  364. tSGSP pSGSP;
  365. private:
  366. // **************************************** ToolHelp32 ************************
  367. #define MAX_MODULE_NAME32 255
  368. #define TH32CS_SNAPMODULE 0x00000008
  369. #pragma pack( push, 8 )
  370. typedef struct tagMODULEENTRY32
  371. {
  372. DWORD dwSize;
  373. DWORD th32ModuleID; // This module
  374. DWORD th32ProcessID; // owning process
  375. DWORD GlblcntUsage; // Global usage count on the module
  376. DWORD ProccntUsage; // Module usage count in th32ProcessID's context
  377. BYTE * modBaseAddr; // Base address of module in th32ProcessID's context
  378. DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr
  379. HMODULE hModule; // The hModule of this module in th32ProcessID's context
  380. char szModule[MAX_MODULE_NAME32 + 1];
  381. char szExePath[MAX_PATH];
  382. } MODULEENTRY32;
  383. typedef MODULEENTRY32 * PMODULEENTRY32;
  384. typedef MODULEENTRY32 * LPMODULEENTRY32;
  385. #pragma pack( pop )
  386. BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid)
  387. {
  388. // CreateToolhelp32Snapshot()
  389. typedef HANDLE (__stdcall *tCT32S)(DWORD dwFlags, DWORD th32ProcessID);
  390. // Module32First()
  391. typedef BOOL (__stdcall *tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
  392. // Module32Next()
  393. typedef BOOL (__stdcall *tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
  394. // try both dlls...
  395. const TCHAR *dllname[] = { _T("kernel32.dll"), _T("tlhelp32.dll") };
  396. HINSTANCE hToolhelp = NULL;
  397. tCT32S pCT32S = NULL;
  398. tM32F pM32F = NULL;
  399. tM32N pM32N = NULL;
  400. HANDLE hSnap;
  401. MODULEENTRY32 me;
  402. me.dwSize = sizeof(me);
  403. BOOL keepGoing;
  404. size_t i;
  405. for (i = 0; i<(sizeof(dllname) / sizeof(dllname[0])); i++ )
  406. {
  407. hToolhelp = LoadLibrary( dllname[i] );
  408. if (hToolhelp == NULL)
  409. continue;
  410. pCT32S = (tCT32S) GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");
  411. pM32F = (tM32F) GetProcAddress(hToolhelp, "Module32First");
  412. pM32N = (tM32N) GetProcAddress(hToolhelp, "Module32Next");
  413. if ( (pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL) )
  414. break; // found the functions!
  415. FreeLibrary(hToolhelp);
  416. hToolhelp = NULL;
  417. }
  418. if (hToolhelp == NULL)
  419. return FALSE;
  420. hSnap = pCT32S( TH32CS_SNAPMODULE, pid );
  421. if (hSnap == (HANDLE) -1)
  422. {
  423. FreeLibrary(hToolhelp);
  424. return FALSE;
  425. }
  426. keepGoing = !!pM32F( hSnap, &me );
  427. int cnt = 0;
  428. while (keepGoing)
  429. {
  430. this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64) me.modBaseAddr, me.modBaseSize);
  431. cnt++;
  432. keepGoing = !!pM32N( hSnap, &me );
  433. }
  434. CloseHandle(hSnap);
  435. FreeLibrary(hToolhelp);
  436. if (cnt <= 0)
  437. return FALSE;
  438. return TRUE;
  439. } // GetModuleListTH32
  440. // **************************************** PSAPI ************************
  441. typedef struct _MODULEINFO {
  442. LPVOID lpBaseOfDll;
  443. DWORD SizeOfImage;
  444. LPVOID EntryPoint;
  445. } MODULEINFO, *LPMODULEINFO;
  446. BOOL GetModuleListPSAPI(HANDLE hProcess)
  447. {
  448. // EnumProcessModules()
  449. typedef BOOL (__stdcall *tEPM)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded );
  450. // GetModuleFileNameEx()
  451. typedef DWORD (__stdcall *tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );
  452. // GetModuleBaseName()
  453. typedef DWORD (__stdcall *tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );
  454. // GetModuleInformation()
  455. typedef BOOL (__stdcall *tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize );
  456. HINSTANCE hPsapi;
  457. tEPM pEPM;
  458. tGMFNE pGMFNE;
  459. tGMBN pGMBN;
  460. tGMI pGMI;
  461. DWORD i;
  462. //ModuleEntry e;
  463. DWORD cbNeeded;
  464. MODULEINFO mi;
  465. HMODULE *hMods = 0;
  466. char *tt = NULL;
  467. char *tt2 = NULL;
  468. const SIZE_T TTBUFLEN = 8096;
  469. int cnt = 0;
  470. hPsapi = LoadLibrary( _T("psapi.dll") );
  471. if (hPsapi == NULL)
  472. return FALSE;
  473. pEPM = (tEPM) GetProcAddress( hPsapi, "EnumProcessModules" );
  474. pGMFNE = (tGMFNE) GetProcAddress( hPsapi, "GetModuleFileNameExA" );
  475. pGMBN = (tGMFNE) GetProcAddress( hPsapi, "GetModuleBaseNameA" );
  476. pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" );
  477. if ( (pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL) )
  478. {
  479. // we couldn´t find all functions
  480. FreeLibrary(hPsapi);
  481. return FALSE;
  482. }
  483. hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof HMODULE));
  484. tt = (char*) malloc(sizeof(char) * TTBUFLEN);
  485. tt2 = (char*) malloc(sizeof(char) * TTBUFLEN);
  486. if ( (hMods == NULL) || (tt == NULL) || (tt2 == NULL) )
  487. goto cleanup;
  488. if ( ! pEPM( hProcess, hMods, TTBUFLEN, &cbNeeded ) )
  489. {
  490. //_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle );
  491. goto cleanup;
  492. }
  493. if ( cbNeeded > TTBUFLEN )
  494. {
  495. //_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) );
  496. goto cleanup;
  497. }
  498. for ( i = 0; i < cbNeeded / sizeof hMods[0]; i++ )
  499. {
  500. // base address, size
  501. pGMI(hProcess, hMods[i], &mi, sizeof mi );
  502. // image file name
  503. tt[0] = 0;
  504. pGMFNE(hProcess, hMods[i], tt, TTBUFLEN );
  505. // module name
  506. tt2[0] = 0;
  507. pGMBN(hProcess, hMods[i], tt2, TTBUFLEN );
  508. DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64) mi.lpBaseOfDll, mi.SizeOfImage);
  509. if (dwRes != ERROR_SUCCESS)
  510. this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0);
  511. cnt++;
  512. }
  513. cleanup:
  514. if (hPsapi != NULL) FreeLibrary(hPsapi);
  515. if (tt2 != NULL) free(tt2);
  516. if (tt != NULL) free(tt);
  517. if (hMods != NULL) free(hMods);
  518. return cnt != 0;
  519. } // GetModuleListPSAPI
  520. DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size)
  521. {
  522. CHAR *szImg = _strdup(img);
  523. CHAR *szMod = _strdup(mod);
  524. DWORD result = ERROR_SUCCESS;
  525. if ( (szImg == NULL) || (szMod == NULL) )
  526. result = ERROR_NOT_ENOUGH_MEMORY;
  527. else
  528. {
  529. if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0)
  530. result = GetLastError();
  531. }
  532. ULONGLONG fileVersion = 0;
  533. if ( (m_parent != NULL) && (szImg != NULL) )
  534. {
  535. // try to retrive the file-version:
  536. if ( (this->m_parent->m_options & StackWalker::RetrieveFileVersion) != 0)
  537. {
  538. VS_FIXEDFILEINFO *fInfo = NULL;
  539. DWORD dwHandle;
  540. DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle);
  541. if (dwSize > 0)
  542. {
  543. LPVOID vData = malloc(dwSize);
  544. if (vData != NULL)
  545. {
  546. if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0)
  547. {
  548. UINT len;
  549. TCHAR szSubBlock[] = _T("\\");
  550. if (VerQueryValue(vData, szSubBlock, (LPVOID*) &fInfo, &len) == 0)
  551. fInfo = NULL;
  552. else
  553. {
  554. fileVersion = ((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32);
  555. }
  556. }
  557. free(vData);
  558. }
  559. }
  560. }
  561. // Retrive some additional-infos about the module
  562. IMAGEHLP_MODULE64_V3 Module;
  563. const char *szSymType = "-unknown-";
  564. if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE)
  565. {
  566. switch(Module.SymType)
  567. {
  568. case SymNone:
  569. szSymType = "-nosymbols-";
  570. break;
  571. case SymCoff: // 1
  572. szSymType = "COFF";
  573. break;
  574. case SymCv: // 2
  575. szSymType = "CV";
  576. break;
  577. case SymPdb: // 3
  578. szSymType = "PDB";
  579. break;
  580. case SymExport: // 4
  581. szSymType = "-exported-";
  582. break;
  583. case SymDeferred: // 5
  584. szSymType = "-deferred-";
  585. break;
  586. case SymSym: // 6
  587. szSymType = "SYM";
  588. break;
  589. case 7: // SymDia:
  590. szSymType = "DIA";
  591. break;
  592. case 8: //SymVirtual:
  593. szSymType = "Virtual";
  594. break;
  595. }
  596. }
  597. LPCSTR pdbName = Module.LoadedImageName;
  598. if (Module.LoadedPdbName[0] != 0)
  599. pdbName = Module.LoadedPdbName;
  600. this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, pdbName, fileVersion);
  601. }
  602. if (szImg != NULL) free(szImg);
  603. if (szMod != NULL) free(szMod);
  604. return result;
  605. }
  606. public:
  607. BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId)
  608. {
  609. // first try toolhelp32
  610. if (GetModuleListTH32(hProcess, dwProcessId))
  611. return true;
  612. // then try psapi
  613. return GetModuleListPSAPI(hProcess);
  614. }
  615. BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V3 *pModuleInfo)
  616. {
  617. memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3));
  618. if(this->pSGMI == NULL)
  619. {
  620. SetLastError(ERROR_DLL_INIT_FAILED);
  621. return FALSE;
  622. }
  623. // First try to use the larger ModuleInfo-Structure
  624. pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);
  625. void *pData = malloc(4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites...
  626. if (pData == NULL)
  627. {
  628. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  629. return FALSE;
  630. }
  631. memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V3));
  632. static bool s_useV3Version = true;
  633. if (s_useV3Version)
  634. {
  635. if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*) pData) != FALSE)
  636. {
  637. // only copy as much memory as is reserved...
  638. memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3));
  639. pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);
  640. free(pData);
  641. return TRUE;
  642. }
  643. s_useV3Version = false; // to prevent unneccessarry calls with the larger struct...
  644. }
  645. // could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)...
  646. pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
  647. memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2));
  648. if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*) pData) != FALSE)
  649. {
  650. // only copy as much memory as is reserved...
  651. memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2));
  652. pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
  653. free(pData);
  654. return TRUE;
  655. }
  656. free(pData);
  657. SetLastError(ERROR_DLL_INIT_FAILED);
  658. return FALSE;
  659. }
  660. };
  661. // #############################################################
  662. StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess)
  663. {
  664. fast=false;
  665. this->m_options = OptionsAll;
  666. this->m_modulesLoaded = FALSE;
  667. this->m_hProcess = hProcess;
  668. this->m_sw = new StackWalkerInternal(this, this->m_hProcess);
  669. this->m_dwProcessId = dwProcessId;
  670. this->m_szSymPath = NULL;
  671. this->m_MaxRecursionCount = 1000;
  672. }
  673. StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess)
  674. {
  675. fast=false;
  676. this->m_options = options;
  677. this->m_modulesLoaded = FALSE;
  678. this->m_hProcess = hProcess;
  679. this->m_sw = new StackWalkerInternal(this, this->m_hProcess);
  680. this->m_dwProcessId = dwProcessId;
  681. if (szSymPath != NULL)
  682. {
  683. this->m_szSymPath = _strdup(szSymPath);
  684. this->m_options |= SymBuildPath;
  685. }
  686. else
  687. this->m_szSymPath = NULL;
  688. this->m_MaxRecursionCount = 1000;
  689. }
  690. StackWalker::~StackWalker()
  691. {
  692. if (m_szSymPath != NULL)
  693. free(m_szSymPath);
  694. m_szSymPath = NULL;
  695. if (this->m_sw != NULL)
  696. delete this->m_sw;
  697. this->m_sw = NULL;
  698. }
  699. BOOL StackWalker::LoadModules()
  700. {
  701. if (this->m_sw == NULL)
  702. {
  703. SetLastError(ERROR_DLL_INIT_FAILED);
  704. return FALSE;
  705. }
  706. if (m_modulesLoaded != FALSE)
  707. return TRUE;
  708. // Build the sym-path:
  709. char *szSymPath = NULL;
  710. if ( (this->m_options & SymBuildPath) != 0)
  711. {
  712. const size_t nSymPathLen = 4096;
  713. szSymPath = (char*) malloc(nSymPathLen);
  714. if (szSymPath == NULL)
  715. {
  716. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  717. return FALSE;
  718. }
  719. szSymPath[0] = 0;
  720. // Now first add the (optional) provided sympath:
  721. if (this->m_szSymPath != NULL)
  722. {
  723. strcat_s(szSymPath, nSymPathLen, this->m_szSymPath);
  724. strcat_s(szSymPath, nSymPathLen, ";");
  725. }
  726. strcat_s(szSymPath, nSymPathLen, ".;");
  727. const size_t nTempLen = 1024;
  728. char szTemp[nTempLen];
  729. // Now add the current directory:
  730. if (GetCurrentDirectoryA(nTempLen, szTemp) > 0)
  731. {
  732. szTemp[nTempLen-1] = 0;
  733. strcat_s(szSymPath, nSymPathLen, szTemp);
  734. strcat_s(szSymPath, nSymPathLen, ";");
  735. }
  736. // Now add the path for the main-module:
  737. if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0)
  738. {
  739. szTemp[nTempLen-1] = 0;
  740. for (char *p = (szTemp+strlen(szTemp)-1); p >= szTemp; --p)
  741. {
  742. // locate the rightmost path separator
  743. if ( (*p == '\\') || (*p == '/') || (*p == ':') )
  744. {
  745. *p = 0;
  746. break;
  747. }
  748. } // for (search for path separator...)
  749. if (strlen(szTemp) > 0)
  750. {
  751. strcat_s(szSymPath, nSymPathLen, szTemp);
  752. strcat_s(szSymPath, nSymPathLen, ";");
  753. }
  754. }
  755. if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0)
  756. {
  757. szTemp[nTempLen-1] = 0;
  758. strcat_s(szSymPath, nSymPathLen, szTemp);
  759. strcat_s(szSymPath, nSymPathLen, ";");
  760. }
  761. if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0)
  762. {
  763. szTemp[nTempLen-1] = 0;
  764. strcat_s(szSymPath, nSymPathLen, szTemp);
  765. strcat_s(szSymPath, nSymPathLen, ";");
  766. }
  767. if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0)
  768. {
  769. szTemp[nTempLen-1] = 0;
  770. strcat_s(szSymPath, nSymPathLen, szTemp);
  771. strcat_s(szSymPath, nSymPathLen, ";");
  772. // also add the "system32"-directory:
  773. strcat_s(szTemp, nTempLen, "\\system32");
  774. strcat_s(szSymPath, nSymPathLen, szTemp);
  775. strcat_s(szSymPath, nSymPathLen, ";");
  776. }
  777. if ( (this->m_options & SymUseSymSrv) != 0)
  778. {
  779. if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0)
  780. {
  781. szTemp[nTempLen-1] = 0;
  782. strcat_s(szSymPath, nSymPathLen, "SRV*");
  783. strcat_s(szSymPath, nSymPathLen, szTemp);
  784. strcat_s(szSymPath, nSymPathLen, "\\websymbols");
  785. strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;");
  786. }
  787. else
  788. strcat_s(szSymPath, nSymPathLen, "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;");
  789. }
  790. } // if SymBuildPath
  791. // First Init the whole stuff...
  792. BOOL bRet = this->m_sw->Init(szSymPath);
  793. if (szSymPath != NULL) free(szSymPath); szSymPath = NULL;
  794. if (bRet == FALSE)
  795. {
  796. this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0);
  797. SetLastError(ERROR_DLL_INIT_FAILED);
  798. return FALSE;
  799. }
  800. bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId);
  801. if (bRet != FALSE)
  802. m_modulesLoaded = TRUE;
  803. return bRet;
  804. }
  805. // The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction
  806. // This has to be done due to a problem with the "hProcess"-parameter in x64...
  807. // Because this class is in no case multi-threading-enabled (because of the limitations
  808. // of dbghelp.dll) it is "safe" to use a static-variable
  809. static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL;
  810. static LPVOID s_readMemoryFunction_UserData = NULL;
  811. BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadProcessMemoryRoutine readMemoryFunction, LPVOID pUserData)
  812. {
  813. SWP_START
  814. CONTEXT c;
  815. CallstackEntry csEntry;
  816. IMAGEHLP_SYMBOL64 *pSym = (IMAGEHLP_SYMBOL64 *) pSym_temp;
  817. StackWalkerInternal::IMAGEHLP_MODULE64_V3 Module;
  818. IMAGEHLP_LINE64 Line;
  819. int frameNum;
  820. bool bLastEntryCalled = true;
  821. int curRecursionCount = 0;
  822. if (m_modulesLoaded == FALSE)
  823. {
  824. memset(pSym, 0, SIZEI(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
  825. pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
  826. pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;
  827. this->LoadModules(); // ignore the result...
  828. }
  829. if (this->m_sw->m_hDbhHelp == NULL)
  830. {
  831. SetLastError(ERROR_DLL_INIT_FAILED);
  832. return FALSE;
  833. }
  834. s_readMemoryFunction = readMemoryFunction;
  835. s_readMemoryFunction_UserData = pUserData;
  836. SWP(0)
  837. if (context == NULL)
  838. {
  839. // If no context is provided, capture the context
  840. if (hThread == GetCurrentThread())
  841. {
  842. GET_CURRENT_CONTEXT(c, USED_CONTEXT_FLAGS);
  843. }
  844. else
  845. {
  846. SuspendThread(hThread);
  847. memset(&c, 0, sizeof(CONTEXT));
  848. c.ContextFlags = USED_CONTEXT_FLAGS;
  849. if (GetThreadContext(hThread, &c) == FALSE)
  850. {
  851. ResumeThread(hThread);
  852. return FALSE;
  853. }
  854. }
  855. }
  856. else
  857. c = *context;
  858. SWP(1)
  859. // init STACKFRAME for first call
  860. STACKFRAME64 s; // in/out stackframe
  861. memset(&s, 0, sizeof(s));
  862. DWORD imageType;
  863. #ifdef _M_IX86
  864. // normally, call ImageNtHeader() and use machine info from PE header
  865. imageType = IMAGE_FILE_MACHINE_I386;
  866. s.AddrPC.Offset = c.Eip;
  867. s.AddrPC.Mode = AddrModeFlat;
  868. s.AddrFrame.Offset = c.Ebp;
  869. s.AddrFrame.Mode = AddrModeFlat;
  870. s.AddrStack.Offset = c.Esp;
  871. s.AddrStack.Mode = AddrModeFlat;
  872. #elif _M_X64
  873. imageType = IMAGE_FILE_MACHINE_AMD64;
  874. s.AddrPC.Offset = c.Rip;
  875. s.AddrPC.Mode = AddrModeFlat;
  876. s.AddrFrame.Offset = c.Rsp;
  877. s.AddrFrame.Mode = AddrModeFlat;
  878. s.AddrStack.Offset = c.Rsp;
  879. s.AddrStack.Mode = AddrModeFlat;
  880. #elif _M_IA64
  881. imageType = IMAGE_FILE_MACHINE_IA64;
  882. s.AddrPC.Offset = c.StIIP;
  883. s.AddrPC.Mode = AddrModeFlat;
  884. s.AddrFrame.Offset = c.IntSp;
  885. s.AddrFrame.Mode = AddrModeFlat;
  886. s.AddrBStore.Offset = c.RsBSP;
  887. s.AddrBStore.Mode = AddrModeFlat;
  888. s.AddrStack.Offset = c.IntSp;
  889. s.AddrStack.Mode = AddrModeFlat;
  890. #else
  891. #error "Platform not supported!"
  892. #endif
  893. SWP(2)
  894. memset(&Line, 0, sizeof(Line));
  895. Line.SizeOfStruct = sizeof(Line);
  896. memset(&Module, 0, sizeof(Module));
  897. Module.SizeOfStruct = sizeof(Module);
  898. SWP(3)
  899. for (frameNum = 0; ; ++frameNum )
  900. {
  901. // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64())
  902. // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can
  903. // assume that either you are done, or that the stack is so hosed that the next
  904. // deeper frame could not be found.
  905. // CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386!
  906. if ( ! this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem, this->m_sw->pSFTA, this->m_sw->pSGMB, NULL) )
  907. {
  908. // INFO: "StackWalk64" does not set "GetLastError"...
  909. this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset);
  910. break;
  911. }
  912. csEntry.offset = s.AddrPC.Offset;
  913. csEntry.name[0] = 0;
  914. csEntry.undName[0] = 0;
  915. csEntry.undFullName[0] = 0;
  916. csEntry.offsetFromSmybol = 0;
  917. csEntry.offsetFromLine = 0;
  918. csEntry.lineFileName[0] = 0;
  919. csEntry.lineNumber = 0;
  920. csEntry.loadedImageName[0] = 0;
  921. csEntry.moduleName[0] = 0;
  922. if (s.AddrPC.Offset == s.AddrReturn.Offset)
  923. {
  924. if ( (this->m_MaxRecursionCount > 0) && (curRecursionCount > m_MaxRecursionCount) )
  925. {
  926. this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset);
  927. break;
  928. }
  929. curRecursionCount++;
  930. }
  931. else
  932. curRecursionCount = 0;
  933. if (s.AddrPC.Offset != 0)
  934. {
  935. // we seem to have a valid PC
  936. // show procedure info (SymGetSymFromAddr64())
  937. if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol), pSym) != FALSE)
  938. {
  939. MyStrCpy(csEntry.name, STACKWALK_MAX_NAMELEN, pSym->Name);
  940. if(!fast)
  941. {
  942. // UnDecorateSymbolName()
  943. this->m_sw->pUDSN( pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY );
  944. this->m_sw->pUDSN( pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE );
  945. }
  946. }
  947. else
  948. {
  949. this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset);
  950. }
  951. if(!fast)
  952. {
  953. // show line number info, NT5.0-method (SymGetLineFromAddr64())
  954. if (this->m_sw->pSGLFA != NULL )
  955. { // yes, we have SymGetLineFromAddr64()
  956. if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line) != FALSE)
  957. {
  958. csEntry.lineNumber = Line.LineNumber;
  959. MyStrCpy(csEntry.lineFileName, STACKWALK_MAX_NAMELEN, Line.FileName);
  960. }
  961. else
  962. {
  963. this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset);
  964. }
  965. } // yes, we have SymGetLineFromAddr64()
  966. // show module info (SymGetModuleInfo64())
  967. if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module ) != FALSE)
  968. { // got module info OK
  969. switch ( Module.SymType )
  970. {
  971. case SymNone:
  972. csEntry.symTypeString = "-nosymbols-";
  973. break;
  974. case SymCoff:
  975. csEntry.symTypeString = "COFF";
  976. break;
  977. case SymCv:
  978. csEntry.symTypeString = "CV";
  979. break;
  980. case SymPdb:
  981. csEntry.symTypeString = "PDB";
  982. break;
  983. case SymExport:
  984. csEntry.symTypeString = "-exported-";
  985. break;
  986. case SymDeferred:
  987. csEntry.symTypeString = "-deferred-";
  988. break;
  989. case SymSym:
  990. csEntry.symTypeString = "SYM";
  991. break;
  992. #if API_VERSION_NUMBER >= 9
  993. case SymDia:
  994. csEntry.symTypeString = "DIA";
  995. break;
  996. #endif
  997. case 8: //SymVirtual:
  998. csEntry.symTypeString = "Virtual";
  999. break;
  1000. default:
  1001. //_snprintf( ty, sizeof ty, "symtype=%ld", (long) Module.SymType );
  1002. csEntry.symTypeString = NULL;
  1003. break;
  1004. }
  1005. MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, Module.ModuleName);
  1006. csEntry.baseOfImage = Module.BaseOfImage;
  1007. MyStrCpy(csEntry.loadedImageName, STACKWALK_MAX_NAMELEN, Module.LoadedImageName);
  1008. } // got module info OK
  1009. else
  1010. {
  1011. this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset);
  1012. }
  1013. }
  1014. } // we seem to have a valid PC
  1015. CallstackEntryType et = nextEntry;
  1016. if (frameNum == 0)
  1017. et = firstEntry;
  1018. bLastEntryCalled = false;
  1019. this->OnCallstackEntry(et, csEntry);
  1020. if (s.AddrReturn.Offset == 0)
  1021. {
  1022. bLastEntryCalled = true;
  1023. this->OnCallstackEntry(lastEntry, csEntry);
  1024. SetLastError(ERROR_SUCCESS);
  1025. break;
  1026. }
  1027. } // for ( frameNum )
  1028. SWP(4)
  1029. if (bLastEntryCalled == false)
  1030. this->OnCallstackEntry(lastEntry, csEntry);
  1031. SWP(5)
  1032. if (context == NULL)
  1033. ResumeThread(hThread);
  1034. SWP(6)
  1035. return TRUE;
  1036. }
  1037. BOOL __stdcall StackWalker::myReadProcMem(
  1038. HANDLE hProcess,
  1039. DWORD64 qwBaseAddress,
  1040. PVOID lpBuffer,
  1041. DWORD nSize,
  1042. LPDWORD lpNumberOfBytesRead
  1043. )
  1044. {
  1045. if (s_readMemoryFunction == NULL)
  1046. {
  1047. SIZE_T st;
  1048. BOOL bRet = ReadProcessMemory(hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, &st);
  1049. *lpNumberOfBytesRead = (DWORD) st;
  1050. //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet);
  1051. return bRet;
  1052. }
  1053. else
  1054. {
  1055. return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, s_readMemoryFunction_UserData);
  1056. }
  1057. }
  1058. void StackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)
  1059. {
  1060. CHAR buffer[STACKWALK_MAX_NAMELEN];
  1061. if (fileVersion == 0)
  1062. _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName);
  1063. else
  1064. {
  1065. DWORD v4 = (DWORD) ( fileVersion & 0xFFFF);
  1066. DWORD v3 = (DWORD) ((fileVersion>>16) & 0xFFFF);
  1067. DWORD v2 = (DWORD) ((fileVersion>>32) & 0xFFFF);
  1068. DWORD v1 = (DWORD) ((fileVersion>>48) & 0xFFFF);
  1069. _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName, v1, v2, v3, v4);
  1070. }
  1071. OnOutput(buffer);
  1072. }
  1073. void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry)
  1074. {
  1075. CHAR buffer[STACKWALK_MAX_NAMELEN];
  1076. if ( (eType != lastEntry) && (entry.offset != 0) )
  1077. {
  1078. if (entry.name[0] == 0)
  1079. MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, "(function-name not available)");
  1080. if (entry.undName[0] != 0)
  1081. MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undName);
  1082. if (entry.undFullName[0] != 0)
  1083. MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undFullName);
  1084. if (entry.lineFileName[0] == 0)
  1085. {
  1086. MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)");
  1087. if (entry.moduleName[0] == 0)
  1088. MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, "(module-name not available)");
  1089. _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%p (%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name);
  1090. }
  1091. else
  1092. _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, entry.name);
  1093. buffer[STACKWALK_MAX_NAMELEN-1] = 0;
  1094. OnOutput(buffer);
  1095. }
  1096. }
  1097. void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
  1098. {
  1099. CHAR buffer[STACKWALK_MAX_NAMELEN];
  1100. _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, (LPVOID) addr);
  1101. OnOutput(buffer);
  1102. }
  1103. void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
  1104. {
  1105. CHAR buffer[STACKWALK_MAX_NAMELEN];
  1106. _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName);
  1107. OnOutput(buffer);
  1108. // Also display the OS-version
  1109. #if _MSC_VER <= 1200
  1110. OSVERSIONINFOA ver;
  1111. ZeroMemory(&ver, sizeof(OSVERSIONINFOA));
  1112. ver.dwOSVersionInfoSize = sizeof(ver);
  1113. if (GetVersionExA(&ver) != FALSE)
  1114. {
  1115. _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n",
  1116. ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
  1117. ver.szCSDVersion);
  1118. OnOutput(buffer);
  1119. }
  1120. #else
  1121. OSVERSIONINFOEXA ver;
  1122. ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA));
  1123. ver.dwOSVersionInfoSize = sizeof(ver);
  1124. if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE)
  1125. {
  1126. _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n",
  1127. ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
  1128. ver.szCSDVersion, ver.wSuiteMask, ver.wProductType);
  1129. OnOutput(buffer);
  1130. }
  1131. #endif
  1132. }
  1133. void StackWalker::OnOutput(LPCSTR buffer)
  1134. {
  1135. OutputDebugStringA(buffer);
  1136. }