LogMessage::~LogMessage() { if (severity_ == LogSeverity::LOG_FATAL) { stream_ << "\n"; StackWalker walker; walker.DumpCallStack(stream_); } stream_ << std::endl; std::string msg = stream_.str(); if (g_logging_dest & LoggingDestination::LOG_TO_SYSTEM_DEBUG_LOG) { OutputDebugStringA(msg.c_str()); // Also writes to standard error stream. fwrite(msg.data(), sizeof(char), msg.length(), stderr); fflush(stderr); } else if (severity_ >= kAlwaysPrintErrorMinLevel) { fwrite(msg.data(), sizeof(char), msg.length(), stderr); fflush(stderr); } // If `InitLogFile` wasn't called at the start of the program, do it on the spot. // However, if we unfortunately failed to initialize the log file, just skip the writting. // Note that, if more than one thread in here try to call `InitLogFile`, there will be a // race condition. This is why you should call `ConfigureLoggingSettings` at start. if ((g_logging_dest & LoggingDestination::LOG_TO_FILE) && InitLogFile()) { DWORD bytes_written = 0; WriteFile(g_log_file, msg.data(), static_cast<DWORD>(msg.length() * sizeof(char)), &bytes_written, nullptr); } }
void DumpStack() { StackWalker walker; CONTEXT c; memset(&c,0,sizeof(c)); GET_CURRENT_CONTEXT(c,CONTEXT_FULL); walker.DumpStack(NULL,20,&c); }
LONG WINAPI DetourApplicationCrashHandler(EXCEPTION_POINTERS *pException) { StackWalker sw; EXCEPTION_RECORD *xr = pException->ExceptionRecord; CONTEXT *xc = pException->ContextRecord; DEBUG_INFO("Eip 0x%08x\n",xc->Eip); sw.ShowCallstack(GetCurrentThread(), pException->ContextRecord,NULL,NULL); return EXCEPTION_EXECUTE_HANDLER; }
void DL_Debug::Debug::AssertMessage(const char *aFileName, int aLine, const char *aFunctionName, const wchar_t *aString) { myDebugFile << "\nFilename: " << aFileName << "\n" << "Line: " << aLine << "\n" << "Function: " << aFunctionName << "\n" << "Message: " << aString << "\n"; StackWalker st; st.ShowCallstack(); std::wstringstream ss; ss << aFileName; myDebugFile.flush(); _wassert(aString, ss.str().c_str(), aLine); }
/////////////////// // Fatal exception void AegisubApp::OnFatalException() { // Attempt to recover file wxFileName origfile(AssFile::top->filename); wxString path = Options.AsText(_T("Auto recovery path")); if (path.IsEmpty()) path = folderName; wxFileName dstpath(path); if (!dstpath.IsAbsolute()) path = AegisubApp::folderName + path; path += _T("/"); dstpath.Assign(path); if (!dstpath.DirExists()) wxMkdir(path); wxString filename = path + origfile.GetName() + _T(".RECOVER.ass"); AssFile::top->Save(filename,false,false); // Stack walk #if wxUSE_STACKWALKER == 1 StackWalker walker; walker.WalkFromException(); #endif // Inform user of crash wxMessageBox(_T("Aegisub has encountered a fatal error and will terminate now. The subtitles you were working on were saved to \"") + filename + _T("\", but they might be corrupt."), _T("Fatal error"), wxOK | wxICON_ERROR, NULL); }
void Debug::AssertMessage(const char* aFileName, int aLine, const char* aFunctionName, const char* aString) { time_t t = time(0); // get current system time; struct tm timeinfo; localtime_s(&timeinfo, &t); myDebugFile << timeinfo.tm_hour << ":" << timeinfo.tm_min << ":" << timeinfo.tm_sec << " error" << std::endl; myDebugFile << " Error: " << aString << " in function " << aFunctionName << " line " << aLine << " in file " << aFileName << std::endl; myDebugFile.flush(); StackWalker aStackWalker; aStackWalker.ShowCallstack(); size_t* a(NULL); wchar_t tmpFileName[256]; mbstowcs_s(a, tmpFileName, aFileName, 256); wchar_t tmpString[256]; mbstowcs_s(a, tmpString, aString, 256); _wassert(tmpString, tmpFileName, aLine); }
static inline void printStackTrace(FILE *out = stderr) { fprintf(out, "Stack Trace:\n"); StackWalker sw; sw.ShowCallstack(); }
LONG WINAPI ExceptionFilter(EXCEPTION_POINTERS* exceptionInfo) { if ( IsDebuggerPresent() ) return EXCEPTION_CONTINUE_SEARCH ; THREADENTRY32 te32; DWORD myThreadId = GetCurrentThreadId(); DWORD myProcessId = GetCurrentProcessId(); HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if (hThreadSnap != INVALID_HANDLE_VALUE) { te32.dwSize = sizeof(THREADENTRY32); if (Thread32First(hThreadSnap, &te32)) { do { //todo: 내 프로세스 내의 스레드중 나 자신 스레드만 빼고 멈추게.. ///# 아래 것이 맞다. if (te32.th32ThreadID != myThreadId) if (te32.th32OwnerProcessID == myProcessId && te32.th32ThreadID != myThreadId) { //이건 어떤지? ///# 스레드 ID와 스레드 핸들은 다른거다. SuspendThread( (HANDLE)te32.th32ThreadID ); ///# 아래의 OpenThread로 하는게 맞는겨.. // HANDLE hThread = OpenThread( THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID ); // if ( !hThread ) // { // printf_s( "Open thread error %d\n", GetLastError() ); // continue; // } // // SuspendThread( hThread ); } } while (Thread32Next(hThreadSnap, &te32)); } CloseHandle(hThreadSnap); } std::ofstream historyOut("EduServer_exception.txt", std::ofstream::out); /// 콜히스토리 남기고 historyOut << "========== WorkerThread Call History ==========" << std::endl << std::endl; for (int i = 0; i < MAX_WORKER_THREAD; ++i) { if (GThreadCallHistory[i]) { GThreadCallHistory[i]->DumpOut(historyOut); } } /// 콜성능 남기고 historyOut << "========== WorkerThread Call Performance ==========" << std::endl << std::endl; for (int i = 0; i < MAX_WORKER_THREAD; ++i) { if (GThreadCallElapsedRecord[i]) { GThreadCallElapsedRecord[i]->DumpOut(historyOut); } } /// 콜스택도 남기고 historyOut << "========== Exception Call Stack ==========" << std::endl << std::endl; //todo: StackWalker를 사용하여 historyOut에 현재 스레드의 콜스택 정보 남기기 //exceptionInfo->ContextRecord // 허허 갓동찬님 이걸 다 만드시다니 ///# 좋은 자세. /* STACKFRAME64 stk; memset( &stk, 0, sizeof( stk ) ); stk.AddrPC.Offset = exceptionInfo->ContextRecord->Rip; stk.AddrPC.Mode = AddrModeFlat; stk.AddrStack.Offset = exceptionInfo->ContextRecord->Rsp; stk.AddrStack.Mode = AddrModeFlat; stk.AddrFrame.Offset = exceptionInfo->ContextRecord->Rbp; stk.AddrFrame.Mode = AddrModeFlat; for ( ULONG Frame = 0; ; Frame++ ) { BOOL result = StackWalk64( IMAGE_FILE_MACHINE_I386, // __in DWORD MachineType, GetCurrentProcess(), // __in HANDLE hProcess, GetCurrentThread(), // __in HANDLE hThread, &stk, // __inout LP STACKFRAME64 StackFrame, &exceptionInfo->ContextRecord, // __inout PVOID ContextRecord, NULL, // __in_opt PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, SymFunctionTableAccess64, // __in_opt PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, SymGetModuleBase64, // __in_opt PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, NULL // __in_opt PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress ); //fprintf( gApplSetup.TraceFile, "*** %2d called from %016LX STACK %016LX FRAME %016LX\n", Frame, (ULONG64)stk.AddrPC.Offset, (ULONG64)stk.AddrStack.Offset, (ULONG64)stk.AddrFrame.Offset ); historyOut << "***" << Frame << "called from" << (ULONG64)stk.AddrPC.Offset << "STACK" << (ULONG64)stk.AddrStack.Offset << "FRAME" << (ULONG64)stk.AddrFrame.Offset << std::endl; if ( !result ) break; } */ StackWalker sw; //= StackWalker( myProcessId, OpenProcess( PROCESS_ALL_ACCESS, TRUE, myProcessId) ); sw.LoadModules(); sw.SetOutputStream( &historyOut ); sw.ShowCallstack(); /// 이벤트 로그 남기고 historyOut << "========== Exception Event Log ==========" << std::endl << std::endl; LoggerUtil::EventLogDumpOut(historyOut); historyOut << "========== Exception Event End ==========" << std::endl << std::endl; historyOut.flush(); historyOut.close(); /// 마지막으로 dump file 남기자. MakeDump(exceptionInfo); ExitProcess(1); /// 여기서 쫑 return EXCEPTION_EXECUTE_HANDLER; }
void PrintThreadCallStack(TextFile* textFile, PEXCEPTION_POINTERS exception, HANDLE process, HANDLE thread) { FileStackWalkReporter reporter(textFile); StackWalker stackWalker; stackWalker.walk(exception, &reporter, process, thread); }