main.cpp 源代码如下:// main.cpp
#include "dllexport.h"
#include <windows.h>
#include <string>
#include <imagehlp.h>
#include <shlobj.h>
#include <assert.h>
#include <psapi.h>
#include <tlhelp32.h>
#include "log.h"
#include "formatoutput.h"
static std::string g_sCrashFileName;
static BOOL g_bHandlerSet = FALSE;
static LPTOP_LEVEL_EXCEPTION_FILTER g_prevUnhandledExceptionFilter = nullptr;
DWORD SetSymOptions(BOOL fDebug)
{
DWORD dwSymOptions = SymGetOptions();
// We have more control calling UnDecorateSymbolName directly Also, we
// don't want DbgHelp trying to undemangle MinGW symbols (e.g., from DLL
// exports) behind our back (as it will just strip the leading underscore.)
if (0) {
dwSymOptions |= SYMOPT_UNDNAME;
} else {
dwSymOptions &= ~SYMOPT_UNDNAME;
}
dwSymOptions |= SYMOPT_LOAD_LINES | SYMOPT_OMAP_FIND_NEAREST;
if (TRUE) {
dwSymOptions |= SYMOPT_DEFERRED_LOADS;
}
if (fDebug) {
dwSymOptions |= SYMOPT_DEBUG;
}
#ifdef _WIN64
dwSymOptions |= SYMOPT_INCLUDE_32BIT_MODULES;
#endif
return SymSetOptions(dwSymOptions);
}
BOOL InitializeSym(HANDLE hProcess, BOOL fInvadeProcess)
{
// Provide default symbol search path
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680689.aspx
// http://msdn.microsoft.com/en-gb/library/windows/hardware/ff558829.aspx
std::string sSymSearchPathBuf;
const char *szSymSearchPath = nullptr;
if (getenv("_NT_SYMBOL_PATH") == nullptr && getenv("_NT_ALT_SYMBOL_PATH") == nullptr) {
char szLocalAppData[MAX_PATH];
HRESULT hr = SHGetFolderPathA(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, szLocalAppData);
assert(SUCCEEDED(hr));
if (SUCCEEDED(hr)) {
// Cache symbols in %APPDATA%\drmingw
sSymSearchPathBuf += "srv*";
sSymSearchPathBuf += szLocalAppData;
sSymSearchPathBuf += "\\drmingw*http://msdl.microsoft.com/download/symbols";
szSymSearchPath = sSymSearchPathBuf.c_str();
} else {
// No cache
szSymSearchPath = "srv*http://msdl.microsoft.com/download/symbols";
}
}
return SymInitialize(hProcess, szSymSearchPath, fInvadeProcess);
}
void GenerateExceptionReport(PEXCEPTION_POINTERS pExceptionInfo)
{
// pExceptionInfo 的结构体信息扩展开来如下:
// typedef struct _EXCEPTION_POINTERS {
// DWORD ExceptionCode;
// DWORD ExceptionFlags;
// struct _EXCEPTION_RECORD *ExceptionRecord;
// PVOID ExceptionAddress;
// DWORD NumberParameters;
// ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
//
// DWORD ContextFlags;
// DWORD Dr0;
// DWORD Dr1;
// DWORD Dr2;
// DWORD Dr3;
// DWORD Dr6;
// DWORD Dr7;
// DWORD ControlWord;
// DWORD StatusWord;
// DWORD TagWord;
// DWORD ErrorOffset;
// DWORD ErrorSelector;
// DWORD DataOffset;
// DWORD DataSelector;
// BYTE RegisterArea[SIZE_OF_80387_REGISTERS];
// DWORD Cr0NpxState;
// DWORD SegGs;
// DWORD SegFs;
// DWORD SegEs;
// DWORD SegDs;
// DWORD Edi;
// DWORD Esi;
// DWORD Ebx;
// DWORD Edx;
// DWORD Ecx;
// DWORD Eax;
// DWORD Ebp;
// DWORD Eip;
// DWORD SegCs;
// DWORD EFlags;
// DWORD Esp;
// DWORD SegSs;
// BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
//} EXCEPTION_POINTERS,*PEXCEPTION_POINTERS;
// Start out with a banner
writeLog("-------------------\n\n");
// 打印系统时间
SYSTEMTIME SystemTime;
GetLocalTime(&SystemTime);
char szDateStr[128];
LCID Locale = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
GetDateFormatA(Locale, 0, &SystemTime, "dddd',' MMMM d',' yyyy", szDateStr, _countof(szDateStr));
char szTimeStr[128];
GetTimeFormatA(Locale, 0, &SystemTime, "HH':'mm':'ss", szTimeStr, _countof(szTimeStr));
writeLog("Error occurred on %s at %s.\n\n", szDateStr, szTimeStr);
// 获取当前进程的一个句柄
HANDLE hProcess = GetCurrentProcess();
SetSymOptions(FALSE);
PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
if(InitializeSym(hProcess, TRUE))
{
// 打印崩溃地址信息
dumpException(hProcess, pExceptionRecord);
PCONTEXT pContext = pExceptionInfo->ContextRecord;
assert(pContext);
// XXX: In 64-bits WINE we can get context record that don't match the exception record somehow
#ifdef _WIN64
PVOID ip = (PVOID)pContext->Rip;
#else
PVOID ip = (PVOID)pContext->Eip;
#endif
if(pExceptionRecord->ExceptionAddress != ip)
{
writeLog("warning: inconsistent exception context record\n");
}
// 函数调用栈信息
dumpStack(hProcess, GetCurrentThread(), pContext);
if (!SymCleanup(hProcess)) {
assert(0);
}
}
// 打印调用模块的信息
dumpModules(hProcess);
writeLog("\n");
}
// 当出现未被处理的异常时,会先调用该函数
static LONG WINAPI MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
static LONG nLockNum = 0;
// 实现数的原子性加减
if(1 == InterlockedIncrement(&nLockNum))
{
// SetErrorMode() 函数控制 Windows 是否处理指定类型的严重错误或使调用应用程序来处理它们。
// SEM_FAILCRITICALERRORS: 系统不显示关键错误处理消息框。相反,系统发送错误给调用进程。
// SEM_NOGPFAULTERRORBOX: 系统不显示Windows错误报告对话框。
// SEM_NOALIGNMENTFAULTEXCEPT: 系统会自动修复故障。此功能只支持部分处理器架构。
// SEM_NOOPENFILEERRORBOX:当无法找到文件时不弹出错误对话框。相反,错误返回给调用进程。
UINT oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
// 创建崩溃时写到磁盘的 .RPT 文件
if(nullptr == g_handleCrashFile)
{
g_handleCrashFile = CreateFileA(g_sCrashFileName.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, 0, 0);
}
if(nullptr != g_handleCrashFile)
{
// 在一个文件中设置新的读取位置
SetFilePointer(g_handleCrashFile, 0, 0, FILE_END);
// 主要通过该函数来生成异常报告信息,其中 pExceptionInfo 是异常信息结构体指针。
GenerateExceptionReport(pExceptionInfo);
// 刷新输出缓存区(也就是为了实时写磁盘)
FlushFileBuffers(g_handleCrashFile);
}
// 把错误模式设置回去
SetErrorMode(oldErrorMode);
}
// 实现数的原子性加减
InterlockedDecrement(&nLockNum);
// 以前也设置过异常捕获函数,那么处理完我们的异常信息之后,我们再调用它。
if(g_prevUnhandledExceptionFilter)
return g_prevUnhandledExceptionFilter(pExceptionInfo);
else
return EXCEPTION_CONTINUE_SEARCH;
}
void ExcHndlInit(const char *pCrashFileName)
{
if(nullptr != pCrashFileName)
g_sCrashFileName = pCrashFileName;
else
g_sCrashFileName = "./crash.RPT";
if(FALSE == g_bHandlerSet)
{
// 设置自己的异常捕获函数,返回以前设置的异常捕获函数
g_prevUnhandledExceptionFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
g_bHandlerSet = TRUE;
}
}
formatoutput.h 源代码如下:// formatoutput.h
#ifndef FORMATOUTPUT_H
#define FORMATOUTPUT_H
#include "log.h"
#include "util.h"
BOOL dumpSourceCode(LPCSTR lpFileName, DWORD dwLineNumber)
{
FILE *fp;
unsigned i;
DWORD dwContext = 2;
if ((fp = fopen(lpFileName, "r")) == NULL)
return FALSE;
i = 0;
while (!feof(fp) && ++i <= dwLineNumber + dwContext) {
int c;
if ((int)i >= (int)dwLineNumber - (int)dwContext) {
writeLog(i == dwLineNumber ? ">%5i: " : "%6i: ", i);
while (!feof(fp) && (c = fgetc(fp)) != '\n')
if (isprint(c))
writeLog("%c", c);
writeLog("\n");
} else {
while (!feof(fp) && fgetc(fp) != '\n')
;
}
}
fclose(fp);
return TRUE;
}
void dumpContext(
#ifdef _WIN64
const WOW64_CONTEXT *pContext
#else
const CONTEXT *pContext
#endif
)
{
// Show the registers
writeLog("Registers:\n");
if (pContext->ContextFlags & CONTEXT_INTEGER) {
writeLog("eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n", pContext->Eax,
pContext->Ebx, pContext->Ecx, pContext->Edx, pContext->Esi, pContext->Edi);
}
if (pContext->ContextFlags & CONTEXT_CONTROL) {
writeLog("eip=%08lx esp=%08lx ebp=%08lx iopl=%1lx %s %s %s %s %s %s %s %s %s %s\n",
pContext->Eip, pContext->Esp, pContext->Ebp,
(pContext->EFlags >> 12) & 3, // IOPL level value
pContext->EFlags & 0x00100000 ? "vip" : " ", // VIP (virtual interrupt pending)
pContext->EFlags & 0x00080000 ? "vif" : " ", // VIF (virtual interrupt flag)
pContext->EFlags & 0x00000800 ? "ov" : "nv", // VIF (virtual interrupt flag)
pContext->EFlags & 0x00000400 ? "dn" : "up", // OF (overflow flag)
pContext->EFlags & 0x00000200 ? "ei" : "di", // IF (interrupt enable flag)
pContext->EFlags & 0x00000080 ? "ng" : "pl", // SF (sign flag)
pContext->EFlags & 0x00000040 ? "zr" : "nz", // ZF (zero flag)
pContext->EFlags & 0x00000010 ? "ac" : "na", // AF (aux carry flag)
pContext->EFlags & 0x00000004 ? "po" : "pe", // PF (parity flag)
pContext->EFlags & 0x00000001 ? "cy" : "nc" // CF (carry flag)
);
}
if (pContext->ContextFlags & CONTEXT_SEGMENTS) {
writeLog("cs=%04lx ss=%04lx ds=%04lx es=%04lx fs=%04lx gs=%04lx", pContext->SegCs,
pContext->SegSs, pContext->SegDs, pContext->SegEs, pContext->SegFs,
pContext->SegGs);
if (pContext->ContextFlags & CONTEXT_CONTROL) {
writeLog(" efl=%08lx", pContext->EFlags);
}
} else {
if (pContext->ContextFlags & CONTEXT_CONTROL) {
writeLog(" "
"efl=%08lx",
pContext->EFlags);
}
}
writeLog("\n\n");
}
void dumpStack(HANDLE hProcess, HANDLE hThread, const CONTEXT *pContext)
{
DWORD MachineType;
assert(pContext);
STACKFRAME64 StackFrame;
ZeroMemory(&StackFrame, sizeof StackFrame);
BOOL bWow64 = FALSE;
if (0) { // if (HAVE_WIN64)
IsWow64Process(hProcess, &bWow64);
}
if (bWow64) {
const WOW64_CONTEXT *pWow64Context = reinterpret_cast<const WOW64_CONTEXT *>(pContext);
// NOLINTNEXTLINE(clang-analyzer-core.NullDereference)
assert((pWow64Context->ContextFlags & WOW64_CONTEXT_FULL) == WOW64_CONTEXT_FULL);
#ifdef _WIN64
dumpContext(pWow64Context);
#endif
MachineType = IMAGE_FILE_MACHINE_I386;
StackFrame.AddrPC.Offset = pWow64Context->Eip;
StackFrame.AddrStack.Offset = pWow64Context->Esp;
StackFrame.AddrFrame.Offset = pWow64Context->Ebp;
} else {
// NOLINTNEXTLINE(clang-analyzer-core.NullDereference)
assert((pContext->ContextFlags & CONTEXT_FULL) == CONTEXT_FULL);
#ifndef _WIN64
MachineType = IMAGE_FILE_MACHINE_I386;
dumpContext(pContext); // 打印当时寄存器的信息
StackFrame.AddrPC.Offset = pContext->Eip;
StackFrame.AddrStack.Offset = pContext->Esp;
StackFrame.AddrFrame.Offset = pContext->Ebp;
#else
MachineType = IMAGE_FILE_MACHINE_AMD64;
StackFrame.AddrPC.Offset = pContext->Rip;
StackFrame.AddrStack.Offset = pContext->Rsp;
StackFrame.AddrFrame.Offset = pContext->Rbp;
#endif
}
StackFrame.AddrPC.Mode = AddrModeFlat;
StackFrame.AddrStack.Mode = AddrModeFlat;
StackFrame.AddrFrame.Mode = AddrModeFlat;
/*
* StackWalk64 modifies Context, so pass a copy.
*/
CONTEXT Context = *pContext;
if (MachineType == IMAGE_FILE_MACHINE_I386) {
writeLog("AddrPC Params\n");
} else {
writeLog("AddrPC Params\n");
}
BOOL bInsideWine = []() -> BOOL
{
HMODULE hNtDll = GetModuleHandleA("ntdll");
if (!hNtDll) {
return FALSE;
}
return GetProcAddress(hNtDll, "wine_get_version") != NULL;
}();
DWORD64 PrevFrameStackOffset = StackFrame.AddrStack.Offset - 1;
int nudge = 0;
while (TRUE) {
constexpr int MAX_SYM_NAME_SIZE = 512;
char szSymName[MAX_SYM_NAME_SIZE] = "";
char szFileName[MAX_PATH] = "";
DWORD dwLineNumber = 0;
if (!StackWalk64(MachineType, hProcess, hThread, &StackFrame, &Context,
NULL, // ReadMemoryRoutine
SymFunctionTableAccess64, SymGetModuleBase64,
NULL // TranslateAddress
))
break;
if (MachineType == IMAGE_FILE_MACHINE_I386) {
writeLog("%08lX %08lX %08lX %08lX", (DWORD)StackFrame.AddrPC.Offset,
(DWORD)StackFrame.Params[0], (DWORD)StackFrame.Params[1],
(DWORD)StackFrame.Params[2]);
} else {
writeLog("%016I64X %016I64X %016I64X %016I64X", StackFrame.AddrPC.Offset,
StackFrame.Params[0], StackFrame.Params[1], StackFrame.Params[2]);
}
BOOL bSymbol = TRUE;
BOOL bLine = FALSE;
DWORD dwOffsetFromSymbol = 0;
DWORD64 AddrPC = StackFrame.AddrPC.Offset;
HMODULE hModule = (HMODULE)(INT_PTR)SymGetModuleBase64(hProcess, AddrPC);
char szModule[MAX_PATH];
if (hModule && GetModuleFileNameExA(hProcess, hModule, szModule, MAX_PATH)) {
writeLog(" %s", getBaseName(szModule));
bSymbol = GetSymFromAddr(hProcess, AddrPC + nudge, szSymName, MAX_SYM_NAME_SIZE,
&dwOffsetFromSymbol);
if (bSymbol) {
writeLog("!%s+0x%lx", szSymName, dwOffsetFromSymbol - nudge);
bLine =
GetLineFromAddr(hProcess, AddrPC + nudge, szFileName, MAX_PATH, &dwLineNumber);
if (bLine) {
writeLog(" [%s @ %ld]", szFileName, dwLineNumber);
}
} else {
writeLog("!0x%I64x", AddrPC - (DWORD64)(INT_PTR)hModule);
}
}
writeLog("\n");
if (bLine) {
dumpSourceCode(szFileName, dwLineNumber);
}
// Basic sanity check to make sure the frame is OK. Bail if not.
if (StackFrame.AddrStack.Offset <= PrevFrameStackOffset ||
StackFrame.AddrPC.Offset == 0xBAADF00D) {
break;
}
PrevFrameStackOffset = StackFrame.AddrStack.Offset;
// Wine's StackWalk64 implementation on certain yield never ending
// stack backtraces unless one bails out when AddrFrame is zero.
if (bInsideWine && StackFrame.AddrFrame.Offset == 0) {
break;
}
/*
* When we walk into the callers, StackFrame.AddrPC.Offset will not
* contain the calling function's address, but rather the return
* address. This could be the next statement, or sometimes (for
* no-return functions) a completely different function, so nudge the
* address by one byte to ensure we get the information about the
* calling statement itself.
*/
nudge = -1;
}
writeLog("\n");
}
void dumpException(HANDLE hProcess, PEXCEPTION_RECORD pExceptionRecord)
{
NTSTATUS ExceptionCode = pExceptionRecord->ExceptionCode;
char szModule[MAX_PATH];
LPCSTR lpcszProcess;
HMODULE hModule;
if (GetModuleFileNameExA(hProcess, NULL, szModule, MAX_PATH))
{
lpcszProcess = getBaseName(szModule);
}
else
{
lpcszProcess = "Application";
}
// First print information about the type of fault
writeLog("%s caused", lpcszProcess);
LPCSTR lpcszException = getExceptionString(ExceptionCode);
if (lpcszException) {
LPCSTR lpszArticle;
switch (lpcszException[0]) {
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
lpszArticle = "an";
break;
default:
lpszArticle = "a";
break;
}
writeLog(" %s %s", lpszArticle, lpcszException);
} else {
writeLog(" an Unknown [0x%lX] Exception", ExceptionCode);
}
// Now print information about where the fault occurred
writeLog(" at location %p", pExceptionRecord->ExceptionAddress);
if((hModule = (HMODULE)(INT_PTR)
SymGetModuleBase64(hProcess, (DWORD64)(INT_PTR)pExceptionRecord->ExceptionAddress)) &&
GetModuleFileNameExA(hProcess, hModule, szModule, sizeof szModule))
{
writeLog(" in module %s", getBaseName(szModule));
}
// If the exception was an access violation, print out some additional information, to the error
// log and the debugger.
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082%28v=vs.85%29.aspx
if ((ExceptionCode == EXCEPTION_ACCESS_VIOLATION || ExceptionCode == EXCEPTION_IN_PAGE_ERROR) &&
pExceptionRecord->NumberParameters >= 2)
{
LPCSTR lpszVerb;
switch (pExceptionRecord->ExceptionInformation[0]) {
case 0:
lpszVerb = "Reading from";
break;
case 1:
lpszVerb = "Writing to";
break;
case 8:
lpszVerb = "DEP violation at";
break;
default:
lpszVerb = "Accessing";
break;
}
writeLog(" %s location %p", lpszVerb, (PVOID)pExceptionRecord->ExceptionInformation[1]);
}
writeLog(".\n\n");
}
void dumpModules(HANDLE hProcess)
{
HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetProcessId(hProcess));
if (hModuleSnap == INVALID_HANDLE_VALUE) {
return;
}
DWORD MachineType;
#ifdef _WIN64
BOOL bWow64 = FALSE;
IsWow64Process(hProcess, &bWow64);
if (bWow64) {
MachineType = IMAGE_FILE_MACHINE_I386;
} else {
#else
{
#endif
#ifndef _WIN64
MachineType = IMAGE_FILE_MACHINE_I386;
#else
MachineType = IMAGE_FILE_MACHINE_AMD64;
#endif
}
MODULEENTRY32 me32;
me32.dwSize = sizeof me32;
if (Module32First(hModuleSnap, &me32)) {
do {
if (MachineType == IMAGE_FILE_MACHINE_I386) {
writeLog(
"%08lX-%08lX ",
(DWORD)(DWORD64)me32.modBaseAddr,
(DWORD)(DWORD64)me32.modBaseAddr + me32.modBaseSize
);
} else {
writeLog(
"%016I64X-%016I64X ",
(DWORD64)me32.modBaseAddr,
(DWORD64)me32.modBaseAddr + me32.modBaseSize
);
}
char *ptr = nullptr;
long len = WideCharToMultiByte(CP_ACP, 0, me32.szExePath, -1, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_ACP, 0, me32.szExePath, -1, ptr, len + 1, NULL, NULL);
const char *szBaseName = getBaseName(ptr);
DWORD dwVInfo[4];
if (getModuleVersionInfo(ptr, dwVInfo)) {
writeLog("%-12s\t%lu.%lu.%lu.%lu\n", szBaseName, dwVInfo[0], dwVInfo[1], dwVInfo[2],
dwVInfo[3]);
} else {
writeLog("%s\n", szBaseName);
}
} while (Module32Next(hModuleSnap, &me32));
writeLog("\n");
}
CloseHandle(hModuleSnap);
}
#endif // FORMATOUTPUT_H
util.h 源代码如下:// util.h
#ifndef UTIL_H
#define UTIL_H
#include <windows.h>
#include <imagehlp.h>
const char *getSeparator(const char *szFilename)
{
const char *p, *q;
p = NULL;
q = szFilename;
char c;
do {
c = *q++;
if (c == '\\' || c == '/' || c == ':')
{
p = q;
}
} while (c);
return p;
}
const char *getBaseName(const char *szFilename)
{
const char *pSeparator = getSeparator(szFilename);
if (!pSeparator)
{
return szFilename;
}
return pSeparator;
}
BOOL GetSymFromAddr(HANDLE hProcess,
DWORD64 dwAddress,
LPSTR lpSymName,
DWORD nSize,
LPDWORD lpdwDisplacement)
{
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)malloc(sizeof(SYMBOL_INFO) + nSize * sizeof(char));
DWORD64 dwDisplacement =
0; // Displacement of the input address, relative to the start of the symbol
BOOL bRet;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = nSize;
DWORD dwOptions = SymGetOptions();
bRet = SymFromAddr(hProcess, dwAddress, &dwDisplacement, pSymbol);
if (bRet) {
// Demangle if not done already
if ((dwOptions & SYMOPT_UNDNAME) ||
UnDecorateSymbolName(pSymbol->Name, lpSymName, nSize, UNDNAME_NAME_ONLY) == 0) {
strncpy(lpSymName, pSymbol->Name, nSize);
}
if (lpdwDisplacement) {
*lpdwDisplacement = dwDisplacement;
}
}
free(pSymbol);
return bRet;
}
BOOL GetLineFromAddr(HANDLE hProcess,
DWORD64 dwAddress,
LPSTR lpFileName,
DWORD nSize,
LPDWORD lpLineNumber)
{
IMAGEHLP_LINE64 Line;
DWORD dwDisplacement =
0; // Displacement of the input address, relative to the start of the symbol
// Do the source and line lookup.
memset(&Line, 0, sizeof Line);
Line.SizeOfStruct = sizeof Line;
if (!SymGetLineFromAddr64(hProcess, dwAddress, &dwDisplacement, &Line))
return FALSE;
assert(lpFileName && lpLineNumber);
strncpy(lpFileName, Line.FileName, nSize);
*lpLineNumber = Line.LineNumber;
return TRUE;
}
BOOL getModuleVersionInfo(LPCSTR szModule, DWORD *dwVInfo)
{
DWORD dummy, size;
BOOL success = FALSE;
size = GetFileVersionInfoSizeA(szModule, &dummy);
if (size > 0) {
LPVOID pVer = malloc(size);
ZeroMemory(pVer, size);
if (GetFileVersionInfoA(szModule, 0, size, pVer)) {
VS_FIXEDFILEINFO *ffi;
if (VerQueryValueA(pVer, "\\", (LPVOID *)&ffi, (UINT *)&dummy)) {
dwVInfo[0] = ffi->dwFileVersionMS >> 16;
dwVInfo[1] = ffi->dwFileVersionMS & 0xFFFF;
dwVInfo[2] = ffi->dwFileVersionLS >> 16;
dwVInfo[3] = ffi->dwFileVersionLS & 0xFFFF;
success = TRUE;
}
}
free(pVer);
}
return success;
}
#ifndef STATUS_FATAL_USER_CALLBACK_EXCEPTION
#define STATUS_FATAL_USER_CALLBACK_EXCEPTION ((NTSTATUS)0xC000041DL)
#endif
#ifndef STATUS_CPP_EH_EXCEPTION
#define STATUS_CPP_EH_EXCEPTION ((NTSTATUS)0xE06D7363L)
#endif
#ifndef STATUS_CLR_EXCEPTION
#define STATUS_CLR_EXCEPTION ((NTSTATUS)0xE0434f4DL)
#endif
#ifndef STATUS_WX86_BREAKPOINT
#define STATUS_WX86_BREAKPOINT ((NTSTATUS)0x4000001FL)
#endif
#ifndef STATUS_POSSIBLE_DEADLOCK
#define STATUS_POSSIBLE_DEADLOCK ((DWORD)0xC0000194L)
#endif
LPCSTR getExceptionString(NTSTATUS ExceptionCode)
{
switch (ExceptionCode) {
case EXCEPTION_ACCESS_VIOLATION: // 0xC0000005
return "Access Violation";
case EXCEPTION_IN_PAGE_ERROR: // 0xC0000006
return "In Page Error";
case EXCEPTION_INVALID_HANDLE: // 0xC0000008
return "Invalid Handle";
case EXCEPTION_ILLEGAL_INSTRUCTION: // 0xC000001D
return "Illegal Instruction";
case EXCEPTION_NONCONTINUABLE_EXCEPTION: // 0xC0000025
return "Cannot Continue";
case EXCEPTION_INVALID_DISPOSITION: // 0xC0000026
return "Invalid Disposition";
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: // 0xC000008C
return "Array bounds exceeded";
case EXCEPTION_FLT_DENORMAL_OPERAND: // 0xC000008D
return "Floating-point denormal operand";
case EXCEPTION_FLT_DIVIDE_BY_ZERO: // 0xC000008E
return "Floating-point division by zero";
case EXCEPTION_FLT_INEXACT_RESULT: // 0xC000008F
return "Floating-point inexact result";
case EXCEPTION_FLT_INVALID_OPERATION: // 0xC0000090
return "Floating-point invalid operation";
case EXCEPTION_FLT_OVERFLOW: // 0xC0000091
return "Floating-point overflow";
case EXCEPTION_FLT_STACK_CHECK: // 0xC0000092
return "Floating-point stack check";
case EXCEPTION_FLT_UNDERFLOW: // 0xC0000093
return "Floating-point underflow";
case EXCEPTION_INT_DIVIDE_BY_ZERO: // 0xC0000094
return "Integer division by zero";
case EXCEPTION_INT_OVERFLOW: // 0xC0000095
return "Integer overflow";
case EXCEPTION_PRIV_INSTRUCTION: // 0xC0000096
return "Privileged instruction";
case EXCEPTION_STACK_OVERFLOW: // 0xC00000FD
return "Stack Overflow";
case EXCEPTION_POSSIBLE_DEADLOCK: // 0xC0000194
return "Possible deadlock condition";
case STATUS_FATAL_USER_CALLBACK_EXCEPTION: // 0xC000041D
return "Fatal User Callback Exception";
case STATUS_ASSERTION_FAILURE: // 0xC0000420
return "Assertion failure";
case STATUS_CLR_EXCEPTION: // 0xE0434f4D
return "CLR exception";
case STATUS_CPP_EH_EXCEPTION: // 0xE06D7363
return "C++ exception handling exception";
case EXCEPTION_GUARD_PAGE: // 0x80000001
return "Guard Page Exception";
case EXCEPTION_DATATYPE_MISALIGNMENT: // 0x80000002
return "Alignment Fault";
case EXCEPTION_BREAKPOINT: // 0x80000003
return "Breakpoint";
case EXCEPTION_SINGLE_STEP: // 0x80000004
return "Single Step";
case STATUS_WX86_BREAKPOINT: // 0x4000001F
return "Breakpoint";
case DBG_TERMINATE_THREAD: // 0x40010003
return "Terminate Thread";
case DBG_TERMINATE_PROCESS: // 0x40010004
return "Terminate Process";
case DBG_CONTROL_C: // 0x40010005
return "Control+C";
case DBG_CONTROL_BREAK: // 0x40010008
return "Control+Break";
case 0x406D1388:
return "Thread Name Exception";
case RPC_S_UNKNOWN_IF:
return "Unknown Interface";
case RPC_S_SERVER_UNAVAILABLE:
return "Server Unavailable";
default:
return NULL;
}
}
#endif // UTIL_H