升龙物业 老版本 ocx IPO, 加密狗 转值班电话

ExceptionHandler.cpp 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. // ExceptionHandler.cpp Version 1.4
  2. //
  3. // Copyright ?1998 Bruce Dawson
  4. //
  5. // This source file contains the exception handler for recording error
  6. // information after crashes. See ExceptionHandler.h for information
  7. // on how to hook it in.
  8. //
  9. // Author: Bruce Dawson
  10. // brucedawson@cygnus-software.com
  11. //
  12. // Modified by: Hans Dietrich
  13. // hdietrich2@hotmail.com
  14. //
  15. // Version 1.4: - Added invocation of XCrashReport.exe
  16. //
  17. // Version 1.3: - Added minidump output
  18. //
  19. // Version 1.1: - reformatted output for XP-like error report
  20. // - added ascii output to stack dump
  21. //
  22. // A paper by the original author can be found at:
  23. // http://www.cygnus-software.com/papers/release_debugging.html
  24. //
  25. ///////////////////////////////////////////////////////////////////////////////
  26. // Disable warnings generated by the Windows header files.
  27. #pragma warning(disable : 4514)
  28. #pragma warning(disable : 4201)
  29. #define _WIN32_WINDOWS 0x0500 // for IsDebuggerPresent
  30. // comment out this line if you don't want minidumps
  31. #define XCRASHREPORT_WRITE_MINIDUMP
  32. // does not require MFC; use 'Not using precompiled headers'
  33. #include "windows.h"
  34. #include <tchar.h>
  35. #include "GetWinVer.h"
  36. #include "miniversion.h"
  37. #include "dbghelp.h"
  38. #include "CrashFileNames.h"
  39. #ifndef _countof
  40. #define _countof(array) (sizeof(array)/sizeof(array[0]))
  41. #endif
  42. const int NumCodeBytes = 16; // Number of code bytes to record.
  43. const int MaxStackDump = 3072; // Maximum number of DWORDS in stack dumps.
  44. const int StackColumns = 4; // Number of columns in stack dump.
  45. #define ONEK 1024
  46. #define SIXTYFOURK (64*ONEK)
  47. #define ONEM (ONEK*ONEK)
  48. #define ONEG (ONEK*ONEK*ONEK)
  49. ///////////////////////////////////////////////////////////////////////////////
  50. // lstrrchr (avoid the C Runtime )
  51. static TCHAR * lstrrchr(LPCTSTR string, int ch)
  52. {
  53. TCHAR *start = (TCHAR *)string;
  54. while (*string++) /* find end of string */
  55. ;
  56. /* search towards front */
  57. while (--string != start && *string != (TCHAR) ch)
  58. ;
  59. if (*string == (TCHAR) ch) /* char found ? */
  60. return (TCHAR *)string;
  61. return NULL;
  62. }
  63. ///////////////////////////////////////////////////////////////////////////////
  64. // hprintf behaves similarly to printf, with a few vital differences.
  65. // It uses wvsprintf to do the formatting, which is a system routine,
  66. // thus avoiding C run time interactions. For similar reasons it
  67. // uses WriteFile rather than fwrite.
  68. // The one limitation that this imposes is that wvsprintf, and
  69. // therefore hprintf, cannot handle floating point numbers.
  70. // Too many calls to WriteFile can take a long time, causing
  71. // confusing delays when programs crash. Therefore I implemented
  72. // a simple buffering scheme for hprintf
  73. #define HPRINTF_BUFFER_SIZE (8*1024) // must be at least 2048
  74. static TCHAR hprintf_buffer[HPRINTF_BUFFER_SIZE]; // wvsprintf never prints more than one K.
  75. static int hprintf_index = 0;
  76. ///////////////////////////////////////////////////////////////////////////////
  77. // hflush
  78. static void hflush(HANDLE LogFile)
  79. {
  80. if (hprintf_index > 0)
  81. {
  82. DWORD NumBytes;
  83. WriteFile(LogFile, hprintf_buffer, lstrlen(hprintf_buffer), &NumBytes, 0);
  84. hprintf_index = 0;
  85. }
  86. }
  87. ///////////////////////////////////////////////////////////////////////////////
  88. // hprintf
  89. static void hprintf(HANDLE LogFile, LPCTSTR Format, ...)
  90. {
  91. if (hprintf_index > (HPRINTF_BUFFER_SIZE-1024))
  92. {
  93. DWORD NumBytes;
  94. WriteFile(LogFile, hprintf_buffer, lstrlen(hprintf_buffer), &NumBytes, 0);
  95. hprintf_index = 0;
  96. }
  97. va_list arglist;
  98. va_start( arglist, Format);
  99. hprintf_index += wvsprintf(&hprintf_buffer[hprintf_index], Format, arglist);
  100. va_end( arglist);
  101. }
  102. #ifdef XCRASHREPORT_WRITE_MINIDUMP
  103. ///////////////////////////////////////////////////////////////////////////////
  104. // DumpMiniDump
  105. static void DumpMiniDump(HANDLE hFile, PEXCEPTION_POINTERS excpInfo)
  106. {
  107. if (excpInfo == NULL)
  108. {
  109. // Generate exception to get proper context in dump
  110. __try
  111. {
  112. OutputDebugString(_T("raising exception\r\n"));
  113. RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL);
  114. }
  115. __except(DumpMiniDump(hFile, GetExceptionInformation()),
  116. EXCEPTION_CONTINUE_EXECUTION)
  117. {
  118. }
  119. }
  120. else
  121. {
  122. OutputDebugString(_T("writing minidump\r\n"));
  123. MINIDUMP_EXCEPTION_INFORMATION eInfo;
  124. eInfo.ThreadId = GetCurrentThreadId();
  125. eInfo.ExceptionPointers = excpInfo;
  126. eInfo.ClientPointers = FALSE;
  127. // note: MiniDumpWithIndirectlyReferencedMemory does not work on Win98
  128. MiniDumpWriteDump(
  129. GetCurrentProcess(),
  130. GetCurrentProcessId(),
  131. hFile,
  132. MiniDumpNormal,
  133. excpInfo ? &eInfo : NULL,
  134. NULL,
  135. NULL);
  136. }
  137. }
  138. #endif // XCRASHREPORT_WRITE_MINIDUMP
  139. ///////////////////////////////////////////////////////////////////////////////
  140. // FormatTime
  141. //
  142. // Format the specified FILETIME to output in a human readable format,
  143. // without using the C run time.
  144. static void FormatTime(LPTSTR output, FILETIME TimeToPrint)
  145. {
  146. output[0] = _T('\0');
  147. WORD Date, Time;
  148. if (FileTimeToLocalFileTime(&TimeToPrint, &TimeToPrint) &&
  149. FileTimeToDosDateTime(&TimeToPrint, &Date, &Time))
  150. {
  151. wsprintf(output, _T("%d/%d/%d %02d:%02d:%02d"),
  152. (Date / 32) & 15, Date & 31, (Date / 512) + 1980,
  153. (Time >> 11), (Time >> 5) & 0x3F, (Time & 0x1F) * 2);
  154. }
  155. }
  156. ///////////////////////////////////////////////////////////////////////////////
  157. // DumpModuleInfo
  158. //
  159. // Print information about a code module (DLL or EXE) such as its size,
  160. // location, time stamp, etc.
  161. static bool DumpModuleInfo(HANDLE LogFile, HINSTANCE ModuleHandle, int nModuleNo)
  162. {
  163. bool rc = false;
  164. TCHAR szModName[MAX_PATH*2];
  165. ZeroMemory(szModName, sizeof(szModName));
  166. __try
  167. {
  168. if (GetModuleFileName(ModuleHandle, szModName, sizeof(szModName)-2) > 0)
  169. {
  170. // If GetModuleFileName returns greater than zero then this must
  171. // be a valid code module address. Therefore we can try to walk
  172. // our way through its structures to find the link time stamp.
  173. IMAGE_DOS_HEADER *DosHeader = (IMAGE_DOS_HEADER*)ModuleHandle;
  174. if (IMAGE_DOS_SIGNATURE != DosHeader->e_magic)
  175. return false;
  176. IMAGE_NT_HEADERS *NTHeader = (IMAGE_NT_HEADERS*)((TCHAR *)DosHeader
  177. + DosHeader->e_lfanew);
  178. if (IMAGE_NT_SIGNATURE != NTHeader->Signature)
  179. return false;
  180. // open the code module file so that we can get its file date and size
  181. HANDLE ModuleFile = CreateFile(szModName, GENERIC_READ,
  182. FILE_SHARE_READ, 0, OPEN_EXISTING,
  183. FILE_ATTRIBUTE_NORMAL, 0);
  184. TCHAR TimeBuffer[100];
  185. TimeBuffer[0] = _T('\0');
  186. DWORD FileSize = 0;
  187. if (ModuleFile != INVALID_HANDLE_VALUE)
  188. {
  189. FileSize = GetFileSize(ModuleFile, 0);
  190. FILETIME LastWriteTime;
  191. if (GetFileTime(ModuleFile, 0, 0, &LastWriteTime))
  192. {
  193. FormatTime(TimeBuffer, LastWriteTime);
  194. }
  195. CloseHandle(ModuleFile);
  196. }
  197. hprintf(LogFile, _T("Module %d\r\n"), nModuleNo);
  198. hprintf(LogFile, _T("%s\r\n"), szModName);
  199. hprintf(LogFile, _T("Image Base: 0x%08x Image Size: 0x%08x\r\n"),
  200. NTHeader->OptionalHeader.ImageBase,
  201. NTHeader->OptionalHeader.SizeOfImage),
  202. hprintf(LogFile, _T("Checksum: 0x%08x Time Stamp: 0x%08x\r\n"),
  203. NTHeader->OptionalHeader.CheckSum,
  204. NTHeader->FileHeader.TimeDateStamp);
  205. hprintf(LogFile, _T("File Size: %-10d File Time: %s\r\n"),
  206. FileSize, TimeBuffer);
  207. hprintf(LogFile, _T("Version Information:\r\n"));
  208. CMiniVersion ver(szModName);
  209. TCHAR szBuf[200];
  210. WORD dwBuf[4];
  211. ver.GetCompanyName(szBuf, sizeof(szBuf)-1);
  212. hprintf(LogFile, _T(" Company: %s\r\n"), szBuf);
  213. ver.GetProductName(szBuf, sizeof(szBuf)-1);
  214. hprintf(LogFile, _T(" Product: %s\r\n"), szBuf);
  215. ver.GetFileDescription(szBuf, sizeof(szBuf)-1);
  216. hprintf(LogFile, _T(" FileDesc: %s\r\n"), szBuf);
  217. ver.GetFileVersion(dwBuf);
  218. hprintf(LogFile, _T(" FileVer: %d.%d.%d.%d\r\n"),
  219. dwBuf[0], dwBuf[1], dwBuf[2], dwBuf[3]);
  220. ver.GetProductVersion(dwBuf);
  221. hprintf(LogFile, _T(" ProdVer: %d.%d.%d.%d\r\n"),
  222. dwBuf[0], dwBuf[1], dwBuf[2], dwBuf[3]);
  223. ver.Release();
  224. hprintf(LogFile, _T("\r\n"));
  225. rc = true;
  226. }
  227. }
  228. // Handle any exceptions by continuing from this point.
  229. __except(EXCEPTION_EXECUTE_HANDLER)
  230. {
  231. }
  232. return rc;
  233. }
  234. ///////////////////////////////////////////////////////////////////////////////
  235. // DumpModuleList
  236. //
  237. // Scan memory looking for code modules (DLLs or EXEs). VirtualQuery is used
  238. // to find all the blocks of address space that were reserved or committed,
  239. // and ShowModuleInfo will display module information if they are code
  240. // modules.
  241. static void DumpModuleList(HANDLE LogFile)
  242. {
  243. SYSTEM_INFO SystemInfo;
  244. GetSystemInfo(&SystemInfo);
  245. const size_t PageSize = SystemInfo.dwPageSize;
  246. // Set NumPages to the number of pages in the 4GByte address space,
  247. // while being careful to avoid overflowing ints
  248. const size_t NumPages = 4 * size_t(ONEG / PageSize);
  249. size_t pageNum = 0;
  250. void *LastAllocationBase = 0;
  251. int nModuleNo = 1;
  252. while (pageNum < NumPages)
  253. {
  254. MEMORY_BASIC_INFORMATION MemInfo;
  255. if (VirtualQuery((void *)(pageNum * PageSize), &MemInfo,
  256. sizeof(MemInfo)))
  257. {
  258. if (MemInfo.RegionSize > 0)
  259. {
  260. // Adjust the page number to skip over this block of memory
  261. pageNum += MemInfo.RegionSize / PageSize;
  262. if (MemInfo.State == MEM_COMMIT && MemInfo.AllocationBase >
  263. LastAllocationBase)
  264. {
  265. // Look for new blocks of committed memory, and try
  266. // recording their module names - this will fail
  267. // gracefully if they aren't code modules
  268. LastAllocationBase = MemInfo.AllocationBase;
  269. if (DumpModuleInfo(LogFile,
  270. (HINSTANCE)LastAllocationBase,
  271. nModuleNo))
  272. {
  273. nModuleNo++;
  274. }
  275. }
  276. }
  277. else
  278. pageNum += SIXTYFOURK / PageSize;
  279. }
  280. else
  281. pageNum += SIXTYFOURK / PageSize;
  282. // If VirtualQuery fails we advance by 64K because that is the
  283. // granularity of address space doled out by VirtualAlloc()
  284. }
  285. }
  286. ///////////////////////////////////////////////////////////////////////////////
  287. // DumpSystemInformation
  288. //
  289. // Record information about the user's system, such as processor type, amount
  290. // of memory, etc.
  291. static void DumpSystemInformation(HANDLE LogFile)
  292. {
  293. FILETIME CurrentTime;
  294. GetSystemTimeAsFileTime(&CurrentTime);
  295. TCHAR szTimeBuffer[100];
  296. FormatTime(szTimeBuffer, CurrentTime);
  297. hprintf(LogFile, _T("Error occurred at %s.\r\n"), szTimeBuffer);
  298. TCHAR szModuleName[MAX_PATH*2];
  299. ZeroMemory(szModuleName, sizeof(szModuleName));
  300. if (GetModuleFileName(0, szModuleName, _countof(szModuleName)-2) <= 0)
  301. lstrcpy(szModuleName, _T("Unknown"));
  302. TCHAR szUserName[200];
  303. ZeroMemory(szUserName, sizeof(szUserName));
  304. DWORD UserNameSize = _countof(szUserName)-2;
  305. if (!GetUserName(szUserName, &UserNameSize))
  306. lstrcpy(szUserName, _T("Unknown"));
  307. hprintf(LogFile, _T("%s, run by %s.\r\n"), szModuleName, szUserName);
  308. // print out operating system
  309. TCHAR szWinVer[50], szMajorMinorBuild[50];
  310. int nWinVer;
  311. GetWinVer(szWinVer, &nWinVer, szMajorMinorBuild);
  312. hprintf(LogFile, _T("Operating system: %s (%s).\r\n"),
  313. szWinVer, szMajorMinorBuild);
  314. SYSTEM_INFO SystemInfo;
  315. GetSystemInfo(&SystemInfo);
  316. hprintf(LogFile, _T("%d processor(s), type %d.\r\n"),
  317. SystemInfo.dwNumberOfProcessors, SystemInfo.dwProcessorType);
  318. MEMORYSTATUS MemInfo;
  319. MemInfo.dwLength = sizeof(MemInfo);
  320. GlobalMemoryStatus(&MemInfo);
  321. // Print out info on memory, rounded up.
  322. hprintf(LogFile, _T("%d%% memory in use.\r\n"), MemInfo.dwMemoryLoad);
  323. hprintf(LogFile, _T("%d MBytes physical memory.\r\n"), (MemInfo.dwTotalPhys +
  324. ONEM - 1) / ONEM);
  325. hprintf(LogFile, _T("%d MBytes physical memory free.\r\n"),
  326. (MemInfo.dwAvailPhys + ONEM - 1) / ONEM);
  327. hprintf(LogFile, _T("%d MBytes paging file.\r\n"), (MemInfo.dwTotalPageFile +
  328. ONEM - 1) / ONEM);
  329. hprintf(LogFile, _T("%d MBytes paging file free.\r\n"),
  330. (MemInfo.dwAvailPageFile + ONEM - 1) / ONEM);
  331. hprintf(LogFile, _T("%d MBytes user address space.\r\n"),
  332. (MemInfo.dwTotalVirtual + ONEM - 1) / ONEM);
  333. hprintf(LogFile, _T("%d MBytes user address space free.\r\n"),
  334. (MemInfo.dwAvailVirtual + ONEM - 1) / ONEM);
  335. }
  336. ///////////////////////////////////////////////////////////////////////////////
  337. // GetExceptionDescription
  338. //
  339. // Translate the exception code into something human readable
  340. static const TCHAR *GetExceptionDescription(DWORD ExceptionCode)
  341. {
  342. struct ExceptionNames
  343. {
  344. DWORD ExceptionCode;
  345. TCHAR * ExceptionName;
  346. };
  347. #if 0 // from winnt.h
  348. #define STATUS_WAIT_0 ((DWORD )0x00000000L)
  349. #define STATUS_ABANDONED_WAIT_0 ((DWORD )0x00000080L)
  350. #define STATUS_USER_APC ((DWORD )0x000000C0L)
  351. #define STATUS_TIMEOUT ((DWORD )0x00000102L)
  352. #define STATUS_PENDING ((DWORD )0x00000103L)
  353. #define STATUS_SEGMENT_NOTIFICATION ((DWORD )0x40000005L)
  354. #define STATUS_GUARD_PAGE_VIOLATION ((DWORD )0x80000001L)
  355. #define STATUS_DATATYPE_MISALIGNMENT ((DWORD )0x80000002L)
  356. #define STATUS_BREAKPOINT ((DWORD )0x80000003L)
  357. #define STATUS_SINGLE_STEP ((DWORD )0x80000004L)
  358. #define STATUS_ACCESS_VIOLATION ((DWORD )0xC0000005L)
  359. #define STATUS_IN_PAGE_ERROR ((DWORD )0xC0000006L)
  360. #define STATUS_INVALID_HANDLE ((DWORD )0xC0000008L)
  361. #define STATUS_NO_MEMORY ((DWORD )0xC0000017L)
  362. #define STATUS_ILLEGAL_INSTRUCTION ((DWORD )0xC000001DL)
  363. #define STATUS_NONCONTINUABLE_EXCEPTION ((DWORD )0xC0000025L)
  364. #define STATUS_INVALID_DISPOSITION ((DWORD )0xC0000026L)
  365. #define STATUS_ARRAY_BOUNDS_EXCEEDED ((DWORD )0xC000008CL)
  366. #define STATUS_FLOAT_DENORMAL_OPERAND ((DWORD )0xC000008DL)
  367. #define STATUS_FLOAT_DIVIDE_BY_ZERO ((DWORD )0xC000008EL)
  368. #define STATUS_FLOAT_INEXACT_RESULT ((DWORD )0xC000008FL)
  369. #define STATUS_FLOAT_INVALID_OPERATION ((DWORD )0xC0000090L)
  370. #define STATUS_FLOAT_OVERFLOW ((DWORD )0xC0000091L)
  371. #define STATUS_FLOAT_STACK_CHECK ((DWORD )0xC0000092L)
  372. #define STATUS_FLOAT_UNDERFLOW ((DWORD )0xC0000093L)
  373. #define STATUS_INTEGER_DIVIDE_BY_ZERO ((DWORD )0xC0000094L)
  374. #define STATUS_INTEGER_OVERFLOW ((DWORD )0xC0000095L)
  375. #define STATUS_PRIVILEGED_INSTRUCTION ((DWORD )0xC0000096L)
  376. #define STATUS_STACK_OVERFLOW ((DWORD )0xC00000FDL)
  377. #define STATUS_CONTROL_C_EXIT ((DWORD )0xC000013AL)
  378. #define STATUS_FLOAT_MULTIPLE_FAULTS ((DWORD )0xC00002B4L)
  379. #define STATUS_FLOAT_MULTIPLE_TRAPS ((DWORD )0xC00002B5L)
  380. #define STATUS_ILLEGAL_VLM_REFERENCE ((DWORD )0xC00002C0L)
  381. #endif
  382. ExceptionNames ExceptionMap[] =
  383. {
  384. {0x40010005, _T("a Control-C")},
  385. {0x40010008, _T("a Control-Break")},
  386. {0x80000002, _T("a Datatype Misalignment")},
  387. {0x80000003, _T("a Breakpoint")},
  388. {0xc0000005, _T("an Access Violation")},
  389. {0xc0000006, _T("an In Page Error")},
  390. {0xc0000017, _T("a No Memory")},
  391. {0xc000001d, _T("an Illegal Instruction")},
  392. {0xc0000025, _T("a Noncontinuable Exception")},
  393. {0xc0000026, _T("an Invalid Disposition")},
  394. {0xc000008c, _T("a Array Bounds Exceeded")},
  395. {0xc000008d, _T("a Float Denormal Operand")},
  396. {0xc000008e, _T("a Float Divide by Zero")},
  397. {0xc000008f, _T("a Float Inexact Result")},
  398. {0xc0000090, _T("a Float Invalid Operation")},
  399. {0xc0000091, _T("a Float Overflow")},
  400. {0xc0000092, _T("a Float Stack Check")},
  401. {0xc0000093, _T("a Float Underflow")},
  402. {0xc0000094, _T("an Integer Divide by Zero")},
  403. {0xc0000095, _T("an Integer Overflow")},
  404. {0xc0000096, _T("a Privileged Instruction")},
  405. {0xc00000fD, _T("a Stack Overflow")},
  406. {0xc0000142, _T("a DLL Initialization Failed")},
  407. {0xe06d7363, _T("a Microsoft C++ Exception")},
  408. };
  409. for (int i = 0; i < sizeof(ExceptionMap) / sizeof(ExceptionMap[0]); i++)
  410. if (ExceptionCode == ExceptionMap[i].ExceptionCode)
  411. return ExceptionMap[i].ExceptionName;
  412. return _T("an Unknown exception type");
  413. }
  414. ///////////////////////////////////////////////////////////////////////////////
  415. // GetFilePart
  416. static TCHAR * GetFilePart(LPCTSTR source)
  417. {
  418. TCHAR *result = lstrrchr(source, _T('\\'));
  419. if (result)
  420. result++;
  421. else
  422. result = (TCHAR *)source;
  423. return result;
  424. }
  425. ///////////////////////////////////////////////////////////////////////////////
  426. // DumpStack
  427. static void DumpStack(HANDLE LogFile, DWORD *pStack)
  428. {
  429. hprintf(LogFile, _T("\r\n\r\nStack:\r\n"));
  430. __try
  431. {
  432. // Esp contains the bottom of the stack, or at least the bottom of
  433. // the currently used area.
  434. DWORD* pStackTop;
  435. __asm
  436. {
  437. // Load the top (highest address) of the stack from the
  438. // thread information block. It will be found there in
  439. // Win9x and Windows NT.
  440. mov eax, fs:[4]
  441. mov pStackTop, eax
  442. }
  443. if (pStackTop > pStack + MaxStackDump)
  444. pStackTop = pStack + MaxStackDump;
  445. int Count = 0;
  446. DWORD* pStackStart = pStack;
  447. int nDwordsPrinted = 0;
  448. while (pStack + 1 <= pStackTop)
  449. {
  450. if ((Count % StackColumns) == 0)
  451. {
  452. pStackStart = pStack;
  453. nDwordsPrinted = 0;
  454. hprintf(LogFile, _T("0x%08x: "), pStack);
  455. }
  456. if ((++Count % StackColumns) == 0 || pStack + 2 > pStackTop)
  457. {
  458. hprintf(LogFile, _T("%08x "), *pStack);
  459. nDwordsPrinted++;
  460. int n = nDwordsPrinted;
  461. while (n < 4)
  462. {
  463. hprintf(LogFile, _T(" "));
  464. n++;
  465. }
  466. for (int i = 0; i < nDwordsPrinted; i++)
  467. {
  468. DWORD dwStack = *pStackStart;
  469. for (int j = 0; j < 4; j++)
  470. {
  471. char c = (char)(dwStack & 0xFF);
  472. if (c < 0x20 || c > 0x7E)
  473. c = '.';
  474. #ifdef _UNICODE
  475. WCHAR w = (WCHAR)c;
  476. hprintf(LogFile, _T("%c"), w);
  477. #else
  478. hprintf(LogFile, _T("%c"), c);
  479. #endif
  480. dwStack = dwStack >> 8;
  481. }
  482. pStackStart++;
  483. }
  484. hprintf(LogFile, _T("\r\n"));
  485. }
  486. else
  487. {
  488. hprintf(LogFile, _T("%08x "), *pStack);
  489. nDwordsPrinted++;
  490. }
  491. pStack++;
  492. }
  493. hprintf(LogFile, _T("\r\n"));
  494. }
  495. __except(EXCEPTION_EXECUTE_HANDLER)
  496. {
  497. hprintf(LogFile, _T("Exception encountered during stack dump.\r\n"));
  498. }
  499. }
  500. ///////////////////////////////////////////////////////////////////////////////
  501. // DumpRegisters
  502. static void DumpRegisters(HANDLE LogFile, PCONTEXT Context)
  503. {
  504. // Print out the register values in an XP error window compatible format.
  505. hprintf(LogFile, _T("\r\n"));
  506. hprintf(LogFile, _T("Context:\r\n"));
  507. hprintf(LogFile, _T("EDI: 0x%08x ESI: 0x%08x EAX: 0x%08x\r\n"),
  508. Context->Edi, Context->Esi, Context->Eax);
  509. hprintf(LogFile, _T("EBX: 0x%08x ECX: 0x%08x EDX: 0x%08x\r\n"),
  510. Context->Ebx, Context->Ecx, Context->Edx);
  511. hprintf(LogFile, _T("EIP: 0x%08x EBP: 0x%08x SegCs: 0x%08x\r\n"),
  512. Context->Eip, Context->Ebp, Context->SegCs);
  513. hprintf(LogFile, _T("EFlags: 0x%08x ESP: 0x%08x SegSs: 0x%08x\r\n"),
  514. Context->EFlags, Context->Esp, Context->SegSs);
  515. }
  516. ///////////////////////////////////////////////////////////////////////////////
  517. ///////////////////////////////////////////////////////////////////////////////
  518. //
  519. // RecordExceptionInfo
  520. //
  521. ///////////////////////////////////////////////////////////////////////////////
  522. ///////////////////////////////////////////////////////////////////////////////
  523. int __cdecl RecordExceptionInfo(PEXCEPTION_POINTERS pExceptPtrs,
  524. LPCTSTR lpszMessage)
  525. {
  526. static bool bFirstTime = true;
  527. if (!bFirstTime) // Going recursive! That must mean this routine crashed!
  528. return EXCEPTION_CONTINUE_SEARCH;
  529. bFirstTime = false;
  530. // Create a filename to record the error information to.
  531. // Storing it in the executable directory works well.
  532. TCHAR szModuleName[MAX_PATH*2];
  533. ZeroMemory(szModuleName, sizeof(szModuleName));
  534. if (GetModuleFileName(0, szModuleName, _countof(szModuleName)-2) <= 0)
  535. lstrcpy(szModuleName, _T("Unknown"));
  536. TCHAR *pszFilePart = GetFilePart(szModuleName);
  537. // Extract the file name portion and remove it's file extension
  538. TCHAR szFileName[MAX_PATH*2];
  539. lstrcpy(szFileName, pszFilePart);
  540. TCHAR *lastperiod = lstrrchr(szFileName, _T('.'));
  541. if (lastperiod)
  542. lastperiod[0] = 0;
  543. // Replace the executable filename with our error log file name
  544. lstrcpy(pszFilePart, XCRASHREPORT_ERROR_LOG_FILE);
  545. HANDLE hLogFile = CreateFile(szModuleName, GENERIC_WRITE, 0, 0,
  546. CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, 0);
  547. if (hLogFile == INVALID_HANDLE_VALUE)
  548. {
  549. OutputDebugString(_T("Error creating exception report\r\n"));
  550. return EXCEPTION_CONTINUE_SEARCH;
  551. }
  552. // Append to the error log
  553. SetFilePointer(hLogFile, 0, 0, FILE_END);
  554. // Print out a blank line to separate this error log from any previous ones
  555. //hprintf(hLogFile, _T("\r\n"));
  556. PEXCEPTION_RECORD Exception = pExceptPtrs->ExceptionRecord;
  557. PCONTEXT Context = pExceptPtrs->ContextRecord;
  558. TCHAR szCrashModulePathName[MAX_PATH*2];
  559. ZeroMemory(szCrashModulePathName, sizeof(szCrashModulePathName));
  560. TCHAR *pszCrashModuleFileName = _T("Unknown");
  561. MEMORY_BASIC_INFORMATION MemInfo;
  562. // VirtualQuery can be used to get the allocation base associated with a
  563. // code address, which is the same as the ModuleHandle. This can be used
  564. // to get the filename of the module that the crash happened in.
  565. if (VirtualQuery((void*)Context->Eip, &MemInfo, sizeof(MemInfo)) &&
  566. (GetModuleFileName((HINSTANCE)MemInfo.AllocationBase,
  567. szCrashModulePathName,
  568. sizeof(szCrashModulePathName)-2) > 0))
  569. {
  570. pszCrashModuleFileName = GetFilePart(szCrashModulePathName);
  571. }
  572. // Print out the beginning of the error log in a Win95 error window
  573. // compatible format.
  574. hprintf(hLogFile, _T("%s caused %s (0x%08x) \r\nin module %s at %04x:%08x.\r\n\r\n"),
  575. szFileName, GetExceptionDescription(Exception->ExceptionCode),
  576. Exception->ExceptionCode,
  577. pszCrashModuleFileName, Context->SegCs, Context->Eip);
  578. hprintf(hLogFile, _T("Exception handler called in %s.\r\n"), lpszMessage);
  579. DumpSystemInformation(hLogFile);
  580. // If the exception was an access violation, print out some additional
  581. // information, to the error log and the debugger.
  582. if (Exception->ExceptionCode == STATUS_ACCESS_VIOLATION &&
  583. Exception->NumberParameters >= 2)
  584. {
  585. TCHAR szDebugMessage[1000];
  586. const TCHAR* readwrite = _T("Read from");
  587. if (Exception->ExceptionInformation[0])
  588. readwrite = _T("Write to");
  589. wsprintf(szDebugMessage, _T("%s location %08x caused an access violation.\r\n"),
  590. readwrite, Exception->ExceptionInformation[1]);
  591. #ifdef _DEBUG
  592. // The Visual C++ debugger doesn't actually tell you whether a read
  593. // or a write caused the access violation, nor does it tell what
  594. // address was being read or written. So I fixed that.
  595. OutputDebugString(_T("Exception handler: "));
  596. OutputDebugString(szDebugMessage);
  597. #endif
  598. hprintf(hLogFile, _T("%s"), szDebugMessage);
  599. }
  600. DumpRegisters(hLogFile, Context);
  601. // Print out the bytes of code at the instruction pointer. Since the
  602. // crash may have been caused by an instruction pointer that was bad,
  603. // this code needs to be wrapped in an exception handler, in case there
  604. // is no memory to read. If the dereferencing of code[] fails, the
  605. // exception handler will print '??'.
  606. hprintf(hLogFile, _T("\r\nBytes at CS:EIP:\r\n"));
  607. BYTE * code = (BYTE *)Context->Eip;
  608. for (int codebyte = 0; codebyte < NumCodeBytes; codebyte++)
  609. {
  610. __try
  611. {
  612. hprintf(hLogFile, _T("%02x "), code[codebyte]);
  613. }
  614. __except(EXCEPTION_EXECUTE_HANDLER)
  615. {
  616. hprintf(hLogFile, _T("?? "));
  617. }
  618. }
  619. // Time to print part or all of the stack to the error log. This allows
  620. // us to figure out the call stack, parameters, local variables, etc.
  621. // Esp contains the bottom of the stack, or at least the bottom of
  622. // the currently used area
  623. DWORD* pStack = (DWORD *)Context->Esp;
  624. DumpStack(hLogFile, pStack);
  625. DumpModuleList(hLogFile);
  626. hprintf(hLogFile, _T("\r\n===== [end of %s] =====\r\n"),
  627. XCRASHREPORT_ERROR_LOG_FILE);
  628. hflush(hLogFile);
  629. CloseHandle(hLogFile);
  630. ///////////////////////////////////////////////////////////////////////////
  631. //
  632. // write minidump
  633. //
  634. ///////////////////////////////////////////////////////////////////////////
  635. #ifdef XCRASHREPORT_WRITE_MINIDUMP
  636. // Replace the filename with our minidump file name
  637. lstrcpy(pszFilePart, XCRASHREPORT_MINI_DUMP_FILE);
  638. // Create the file
  639. HANDLE hMiniDumpFile = CreateFile(
  640. szModuleName,
  641. GENERIC_WRITE,
  642. 0,
  643. NULL,
  644. CREATE_ALWAYS,
  645. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
  646. NULL);
  647. // Write the minidump to the file
  648. if (hMiniDumpFile != INVALID_HANDLE_VALUE)
  649. {
  650. DumpMiniDump(hMiniDumpFile, pExceptPtrs);
  651. // Close file
  652. CloseHandle(hMiniDumpFile);
  653. }
  654. #endif // XCRASHREPORT_WRITE_MINIDUMP
  655. if (IsDebuggerPresent())
  656. {
  657. // let the debugger catch this -
  658. // return the magic value which tells Win32 that this handler didn't
  659. // actually handle the exception - so that things will proceed as per
  660. // normal.
  661. return EXCEPTION_CONTINUE_SEARCH;
  662. }
  663. else
  664. {
  665. ///////////////////////////////////////////////////////////////////////
  666. //
  667. // pop up our crash report app
  668. //
  669. ///////////////////////////////////////////////////////////////////////
  670. // Replace the filename with our crash report exe file name
  671. lstrcpy(pszFilePart, XCRASHREPORT_CRASH_REPORT_APP);
  672. TCHAR szCommandLine[MAX_PATH];
  673. lstrcpy(szCommandLine, szModuleName);
  674. lstrcat(szCommandLine, _T(" \"")); // surround app name with quotes
  675. ZeroMemory(szModuleName, sizeof(szModuleName));
  676. GetModuleFileName(0, szModuleName, _countof(szModuleName)-2);
  677. lstrcat(szCommandLine, GetFilePart(szModuleName));
  678. lstrcat(szCommandLine, _T("\""));
  679. STARTUPINFO si;
  680. ZeroMemory(&si, sizeof(si));
  681. si.cb = sizeof(si);
  682. si.dwFlags = STARTF_USESHOWWINDOW;
  683. si.wShowWindow = SW_SHOW;
  684. PROCESS_INFORMATION pi;
  685. ZeroMemory(&pi, sizeof(pi));
  686. if (CreateProcess(
  687. NULL, // name of executable module
  688. szCommandLine, // command line string
  689. NULL, // process attributes
  690. NULL, // thread attributes
  691. FALSE, // handle inheritance option
  692. 0, // creation flags
  693. NULL, // new environment block
  694. NULL, // current directory name
  695. &si, // startup information
  696. &pi)) // process information
  697. {
  698. // XCrashReport.exe was successfully started, so
  699. // suppress the standard crash dialog
  700. CloseHandle( pi.hProcess );
  701. CloseHandle( pi.hThread );
  702. return EXCEPTION_EXECUTE_HANDLER;
  703. }
  704. else
  705. {
  706. // XCrashReport.exe was not started - let
  707. // the standard crash dialog appear
  708. return EXCEPTION_CONTINUE_SEARCH;
  709. }
  710. }
  711. }