forked from LosaDev/ls-2019-source
LosaDev source snapshot 2019
This commit is contained in:
commit
c198676e97
20588 files changed
+8812878
No files matched your search
@@ -0,0 +1,460 @@
|
||||
#include "stdafx.h"
|
||||
#include <malloc.h>
|
||||
#include "File.h"
|
||||
#include "../Minidump/MiniDump.h"
|
||||
|
||||
|
||||
TCHAR MiniDump::m_filename[MAX_PATH];
|
||||
TCHAR MiniDump::m_folername[MAX_PATH];
|
||||
|
||||
CONTEXT MiniDump::m_stackContext;
|
||||
IMAGEHLP_LINE64 MiniDump::m_stackLine;
|
||||
STACKFRAME64 MiniDump::m_stackFrame;
|
||||
BYTE MiniDump::m_stackSymbol[SYM_BUFF_SIZE];
|
||||
TCHAR MiniDump::m_dumpText[BUFF_SIZE];
|
||||
BOOL MiniDump::m_symEngInit = FALSE;
|
||||
|
||||
|
||||
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(
|
||||
HANDLE hProcess,
|
||||
DWORD dwPid,
|
||||
HANDLE hFile,
|
||||
MINIDUMP_TYPE DumpType,
|
||||
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
|
||||
|
||||
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER PreviousExceptionFilter = NULL;
|
||||
|
||||
|
||||
LONG WINAPI UnHandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionInfo)
|
||||
{
|
||||
// 콜스택저장
|
||||
MiniDump::PrintCallStack(exceptionInfo);
|
||||
|
||||
// Windows 2000 이전에는 따로 DBGHELP를 배포해서 설정해 주어야 한다.
|
||||
HMODULE DllHandle = LoadLibrary(_T("DBGHELP.DLL"));
|
||||
if (DllHandle)
|
||||
{
|
||||
MINIDUMPWRITEDUMP MiniDumpWriteDump = reinterpret_cast<MINIDUMPWRITEDUMP>(GetProcAddress(DllHandle, "MiniDumpWriteDump"));
|
||||
if (MiniDumpWriteDump)
|
||||
{
|
||||
TCHAR dumpPath[MAX_PATH] = {0};
|
||||
|
||||
SYSTEMTIME SystemTime;
|
||||
GetLocalTime(&SystemTime);
|
||||
|
||||
_sntprintf_s(
|
||||
dumpPath,
|
||||
_countof(dumpPath),
|
||||
MAX_PATH,
|
||||
_T("%s\\%s(%04d%02d%02d-%02d%02d%02d).dmp"),
|
||||
MiniDump::m_folername,
|
||||
MiniDump::m_filename,
|
||||
SystemTime.wYear,
|
||||
SystemTime.wMonth,
|
||||
SystemTime.wDay,
|
||||
SystemTime.wHour,
|
||||
SystemTime.wMinute,
|
||||
SystemTime.wSecond);
|
||||
|
||||
HANDLE hDumpFile = CreateFile(
|
||||
dumpPath,
|
||||
GENERIC_WRITE,
|
||||
FILE_SHARE_WRITE,
|
||||
NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
NULL);
|
||||
|
||||
if (hDumpFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
_MINIDUMP_EXCEPTION_INFORMATION ExceptionInfo;
|
||||
|
||||
ExceptionInfo.ThreadId = GetCurrentThreadId();
|
||||
ExceptionInfo.ExceptionPointers = exceptionInfo;
|
||||
ExceptionInfo.ClientPointers = NULL;
|
||||
|
||||
BOOL bSuccess = MiniDumpWriteDump(
|
||||
GetCurrentProcess(),
|
||||
GetCurrentProcessId(),
|
||||
hDumpFile,
|
||||
MiniDumpNormal,
|
||||
&ExceptionInfo,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (bSuccess)
|
||||
{
|
||||
CloseHandle(hDumpFile);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
CloseHandle(hDumpFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
BOOL MiniDump::Begin(const TCHAR* filename)
|
||||
{
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
|
||||
TCHAR temp[512];
|
||||
GetCurrentDirectory(_countof(temp), temp);
|
||||
_sntprintf_s(m_folername, _countof(m_folername),_T("%s\\dump"), temp);
|
||||
CreateDirectory(m_folername, NULL);
|
||||
|
||||
_tcscpy_s(m_filename, _countof(m_filename), filename); // 디버깅 해볼것
|
||||
|
||||
PreviousExceptionFilter = SetUnhandledExceptionFilter(UnHandledExceptionFilter);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL MiniDump::End(VOID)
|
||||
{
|
||||
SetUnhandledExceptionFilter(PreviousExceptionFilter);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Operations
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initializes the symbol engine if needed
|
||||
void MiniDump::InitSymEng(void)
|
||||
{
|
||||
if(FALSE == m_symEngInit)
|
||||
{
|
||||
// Set up the symbol engine.
|
||||
DWORD options = SymGetOptions();
|
||||
|
||||
// Turn on line loading.
|
||||
SymSetOptions(options | SYMOPT_LOAD_LINES);
|
||||
|
||||
// Force the invade process flag on.
|
||||
BOOL bRet = SymInitialize(GetCurrentProcess(), NULL , TRUE);
|
||||
m_symEngInit = bRet;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to isolate filling out the stack frame, which is CPU specific.
|
||||
void MiniDump::FillInStackFrame(PCONTEXT contextRecord)
|
||||
{
|
||||
// Initialize the STACKFRAME structure.
|
||||
ZeroMemory(&m_stackFrame, sizeof (STACKFRAME64));
|
||||
|
||||
m_stackFrame.AddrPC.Offset = contextRecord->Eip;
|
||||
m_stackFrame.AddrPC.Mode = AddrModeFlat;
|
||||
m_stackFrame.AddrStack.Offset = contextRecord->Esp;
|
||||
m_stackFrame.AddrStack.Mode = AddrModeFlat;
|
||||
m_stackFrame.AddrFrame.Offset = contextRecord->Ebp;
|
||||
m_stackFrame.AddrFrame.Mode = AddrModeFlat;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Operations
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
BOOL __stdcall CH_ReadProcessMemory( HANDLE hHandle,
|
||||
DWORD64 qwBaseAddress,
|
||||
PVOID lpBuffer,
|
||||
DWORD nSize,
|
||||
LPDWORD lpNumberOfBytesRead)
|
||||
{
|
||||
return (ReadProcessMemory( GetCurrentProcess(),
|
||||
(LPCVOID)qwBaseAddress,
|
||||
lpBuffer,
|
||||
nSize,
|
||||
lpNumberOfBytesRead));
|
||||
}
|
||||
|
||||
DWORD Ansi2Wide(const char * szANSI, wchar_t* szWide, int iWideLen)
|
||||
{
|
||||
int iRet = MultiByteToWideChar( GetACP(),
|
||||
0,
|
||||
szANSI,
|
||||
-1,
|
||||
szWide,
|
||||
iWideLen);
|
||||
return (iRet);
|
||||
}
|
||||
|
||||
|
||||
DWORD Wide2Ansi(const wchar_t* szWide, char * szANSI, int iAnsiLen)
|
||||
{
|
||||
ZeroMemory(szANSI, iAnsiLen);
|
||||
int iRet = WideCharToMultiByte(CP_ACP, 0, szWide, -1, szANSI, iAnsiLen, NULL, NULL);
|
||||
return iRet;
|
||||
}
|
||||
|
||||
// The internal function that does all the stack walking
|
||||
LPCTSTR MiniDump::InternalGetStackTraceString(DWORD options)
|
||||
{
|
||||
// The value that is returned
|
||||
LPCTSTR szRet;
|
||||
// The module base address. I look this up right after the stack
|
||||
// walk to ensure that the module is valid.
|
||||
DWORD64 modBase;
|
||||
|
||||
__try
|
||||
{
|
||||
// Initialize the symbol engine in case it isn't initialized.
|
||||
MiniDump::InitSymEng();
|
||||
|
||||
// Note: If the source file and line number functions are used,
|
||||
// StackWalk can cause an access violation.
|
||||
BOOL ret = StackWalk64 ( IMAGE_FILE_MACHINE_I386,
|
||||
GetCurrentProcess(),
|
||||
GetCurrentThread(),
|
||||
&m_stackFrame,
|
||||
&m_stackContext,
|
||||
CH_ReadProcessMemory,
|
||||
SymFunctionTableAccess64,
|
||||
SymGetModuleBase64,
|
||||
NULL);
|
||||
if((FALSE == ret) || (0 == m_stackFrame.AddrFrame.Offset))
|
||||
{
|
||||
szRet = NULL;
|
||||
__leave;
|
||||
}
|
||||
|
||||
// Before I get too carried away and start calculating
|
||||
// everything, I need to double-check that the address returned
|
||||
// by StackWalk really exists. I've seen cases in which
|
||||
// StackWalk returns TRUE but the address doesn't belong to
|
||||
// a module in the process.
|
||||
modBase = SymGetModuleBase64(GetCurrentProcess(), m_stackFrame.AddrPC.Offset);
|
||||
if(0 == modBase)
|
||||
{
|
||||
szRet = NULL;
|
||||
__leave;
|
||||
}
|
||||
|
||||
int iCurr = 0;
|
||||
|
||||
// At a minimum, put in the address.
|
||||
#ifdef _WIN64
|
||||
iCurr += wsprintf( m_dumpText + iCurr,
|
||||
_T( "0x%016X" ),
|
||||
m_stackFrame.AddrPC.Offset);
|
||||
#else
|
||||
iCurr += wsprintf ( m_dumpText + iCurr,
|
||||
_T("%04X:%08X"),
|
||||
m_stackContext.SegCs,
|
||||
m_stackFrame.AddrPC.Offset);
|
||||
#endif
|
||||
|
||||
// Output the parameters?
|
||||
if(DUMP_PARAMS == (options & DUMP_PARAMS))
|
||||
{
|
||||
iCurr += wsprintf( m_dumpText + iCurr,
|
||||
_T("0x%08X 0x%08X 0x%08X 0x%08X"),
|
||||
m_stackFrame.Params[ 0 ],
|
||||
m_stackFrame.Params[ 1 ],
|
||||
m_stackFrame.Params[ 2 ],
|
||||
m_stackFrame.Params[ 3 ]);
|
||||
}
|
||||
|
||||
// Output the module name.
|
||||
if(DUMP_MODULE == (options & DUMP_MODULE))
|
||||
{
|
||||
iCurr += wsprintf(m_dumpText + iCurr, _T (" "));
|
||||
|
||||
iCurr += GetModuleBaseName( GetCurrentProcess(),
|
||||
(HINSTANCE)modBase,
|
||||
m_dumpText + iCurr,
|
||||
BUFF_SIZE - iCurr);
|
||||
}
|
||||
|
||||
// Output the symbol name?
|
||||
if(DUMP_SYMBOL == (options & DUMP_SYMBOL))
|
||||
{
|
||||
DWORD64 displacement;
|
||||
|
||||
// Start looking up the exception address.
|
||||
PIMAGEHLP_SYMBOL64 symbol = (PIMAGEHLP_SYMBOL64)&m_stackSymbol;
|
||||
ZeroMemory(symbol , SYM_BUFF_SIZE);
|
||||
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
|
||||
symbol->MaxNameLength = SYM_BUFF_SIZE - sizeof(IMAGEHLP_SYMBOL64);
|
||||
symbol->Address = m_stackFrame.AddrPC.Offset;
|
||||
|
||||
if(TRUE == SymGetSymFromAddr64( GetCurrentProcess(),
|
||||
m_stackFrame.AddrPC.Offset,
|
||||
&displacement,
|
||||
symbol))
|
||||
{
|
||||
if(options & ~DUMP_SYMBOL)
|
||||
{
|
||||
iCurr += wsprintf(m_dumpText + iCurr , _T ( "," ));
|
||||
}
|
||||
|
||||
// Copy no more symbol information than there's room
|
||||
// for. Symbols are ANSI
|
||||
int iLen = lstrlenA( symbol->Name );
|
||||
if(iLen > (BUFF_SIZE - iCurr - (MAX_SYM_SIZE + 50)))
|
||||
{
|
||||
// Get some room on the stack to convert the string.
|
||||
lstrcpyn( m_dumpText + iCurr,
|
||||
reinterpret_cast<LPCWSTR>(symbol->Name),
|
||||
BUFF_SIZE - iCurr - 1);
|
||||
|
||||
// Gotta leave now
|
||||
szRet = m_dumpText;
|
||||
__leave;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(displacement > 0)
|
||||
{
|
||||
iCurr += wsprintf ( m_dumpText + iCurr,
|
||||
//_T("%S()+%04d byte(s)"), // for unicode
|
||||
_T("%s()+%04d byte(s)"),
|
||||
symbol->Name,
|
||||
displacement);
|
||||
}
|
||||
else
|
||||
{
|
||||
iCurr += wsprintf ( m_dumpText + iCurr,
|
||||
//_T("%S"), // for unicode
|
||||
_T("%s"),
|
||||
symbol->Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the symbol wasn't found, the source file and line
|
||||
// number won't be found either, so leave now.
|
||||
szRet = m_dumpText;
|
||||
__leave;
|
||||
}
|
||||
}
|
||||
|
||||
// Output the source file and line number information?
|
||||
if(DUMP_SRCLINE == (options & DUMP_SRCLINE))
|
||||
{
|
||||
ZeroMemory(&m_stackLine , sizeof(IMAGEHLP_LINE64));
|
||||
m_stackLine.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
|
||||
DWORD dwLineDisp;
|
||||
if(TRUE == SymGetLineFromAddr64(GetCurrentProcess(),
|
||||
m_stackFrame.AddrPC.Offset,
|
||||
&dwLineDisp,
|
||||
&m_stackLine))
|
||||
{
|
||||
if(options & ~DUMP_SRCLINE)
|
||||
{
|
||||
iCurr += wsprintf(m_dumpText + iCurr , _T ( "," ));
|
||||
}
|
||||
|
||||
// Copy no more of the source file and line number
|
||||
// information than there's room for.
|
||||
int iLen = lstrlenA(m_stackLine.FileName);
|
||||
if(iLen > (BUFF_SIZE - iCurr - (MAX_PATH + 50)))
|
||||
{
|
||||
// Get some room on the stack to convert the string.
|
||||
lstrcpyn(m_dumpText + iCurr,reinterpret_cast<LPCWSTR>(m_stackLine.FileName), BUFF_SIZE - iCurr - 1);
|
||||
|
||||
// Gotta leave now
|
||||
szRet = m_dumpText;
|
||||
__leave;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dwLineDisp > 0)
|
||||
{
|
||||
iCurr += wsprintf( m_dumpText + iCurr,
|
||||
//_T(" %S, line %04d+%04d byte(s)"),
|
||||
_T(" %s, line %04d+%04d byte(s)"),
|
||||
m_stackLine.FileName,
|
||||
m_stackLine.LineNumber,
|
||||
dwLineDisp);
|
||||
}
|
||||
else
|
||||
{
|
||||
iCurr += wsprintf( m_dumpText + iCurr,
|
||||
//_T(" %S, line %04d"),
|
||||
_T(" %s, line %04d"),
|
||||
m_stackLine.FileName,
|
||||
m_stackLine.LineNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
szRet = m_dumpText;
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
szRet = NULL;
|
||||
}
|
||||
return (szRet);
|
||||
}
|
||||
|
||||
LPCTSTR MiniDump::GetFirstStackTraceString(DWORD options, EXCEPTION_POINTERS * exceptionInfo)
|
||||
{
|
||||
if(TRUE == IsBadReadPtr(exceptionInfo, sizeof(EXCEPTION_POINTERS*)))
|
||||
{
|
||||
// Debug(_T("GetFirstStackTraceString - invalid exceptionInfo\r\n"));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
// Get the stack frame filled in.
|
||||
MiniDump:: FillInStackFrame(exceptionInfo->ContextRecord);
|
||||
|
||||
// Copy over the exception pointers fields so I don't corrupt the
|
||||
// real one.
|
||||
m_stackContext = *(exceptionInfo->ContextRecord);
|
||||
|
||||
return (MiniDump::InternalGetStackTraceString(options));
|
||||
}
|
||||
|
||||
LPCTSTR MiniDump::GetNextStackTraceString(DWORD options, EXCEPTION_POINTERS* exceptionInfo)
|
||||
{
|
||||
// All error checking is in InternalGetStackTraceString.
|
||||
// Assume that GetFirstStackTraceString has already initialized the
|
||||
// stack frame information.
|
||||
return (InternalGetStackTraceString(options));
|
||||
}
|
||||
|
||||
void MiniDump::PrintCallStack(struct _EXCEPTION_POINTERS *exceptionInfo)
|
||||
{
|
||||
TCHAR dumpPath[MAX_PATH] = {0};
|
||||
|
||||
SYSTEMTIME SystemTime;
|
||||
GetLocalTime(&SystemTime);
|
||||
|
||||
_sntprintf_s(
|
||||
dumpPath,
|
||||
_countof(dumpPath),
|
||||
MAX_PATH,
|
||||
_T("%s\\%s(%04d%02d%02d-%02d%02d%02d).txt"),
|
||||
MiniDump::m_folername,
|
||||
MiniDump::m_filename,
|
||||
SystemTime.wYear,
|
||||
SystemTime.wMonth,
|
||||
SystemTime.wDay,
|
||||
SystemTime.wHour,
|
||||
SystemTime.wMinute,
|
||||
SystemTime.wSecond);
|
||||
|
||||
FileWriter file;
|
||||
if(file.Open(dumpPath))
|
||||
{
|
||||
// 콜스택 정보
|
||||
DWORD options = DUMP_MODULE | DUMP_SYMBOL | DUMP_SRCLINE; //DUMP_PARAMS
|
||||
const TCHAR* dumpText = GetFirstStackTraceString(options, exceptionInfo);
|
||||
do
|
||||
{
|
||||
file.WriteFormat(_T("%s\r\n"), dumpText);
|
||||
dumpText = GetNextStackTraceString(options, exceptionInfo);
|
||||
}
|
||||
while(NULL != dumpText);
|
||||
|
||||
// 파일저장
|
||||
file.Close();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user