static void crash_handler(int signo) { int logfd = STDERR_FILENO; for (;;) { // Print out the signal write(logfd, C4VERSION ": Caught signal ", sizeof(C4VERSION ": Caught signal ") - 1); switch (signo) { case SIGBUS: write(logfd, "SIGBUS", sizeof("SIGBUS") - 1); break; case SIGILL: write(logfd, "SIGILL", sizeof("SIGILL") - 1); break; case SIGSEGV: write(logfd, "SIGSEGV", sizeof("SIGSEGV") - 1); break; case SIGABRT: write(logfd, "SIGABRT", sizeof("SIGABRT") - 1); break; case SIGINT: write(logfd, "SIGINT", sizeof("SIGINT") - 1); break; case SIGQUIT: write(logfd, "SIGQUIT", sizeof("SIGQUIT") - 1); break; case SIGFPE: write(logfd, "SIGFPE", sizeof("SIGFPE") - 1); break; case SIGTERM: write(logfd, "SIGTERM", sizeof("SIGTERM") - 1); break; } write(logfd, "\n", sizeof("\n") - 1); if (logfd == STDERR_FILENO) logfd = GetLogFD(); else break; if (logfd < 0) break; } // Get the backtrace void *stack[100]; int count = backtrace(stack, 100); // Print it out backtrace_symbols_fd(stack, count, STDERR_FILENO); // Also to the log file if (logfd >= 0) backtrace_symbols_fd(stack, count, logfd); // Bye. _exit(C4XRV_Failure); }
LONG WINAPI GenerateDump(EXCEPTION_POINTERS* pExceptionPointers) { enum { MDST_BuildId = LastReservedStream + 1 }; if (!FirstCrash) return EXCEPTION_EXECUTE_HANDLER; FirstCrash = false; // Open dump file // Work on the assumption that the config isn't corrupted wchar_t *filename = reinterpret_cast<wchar_t*>(DumpBuffer); const size_t filename_buffer_size = DumpBufferSize / sizeof(wchar_t); if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, ::Config.General.UserDataPath, strnlen(::Config.General.UserDataPath, sizeof(::Config.General.UserDataPath)), filename, filename_buffer_size)) { // Conversion failed; the likely reason for this is a corrupted config. assert (GetLastError() == ERROR_NO_UNICODE_TRANSLATION); // Fall back to the temporary files directory to write dump. DWORD temp_size = GetTempPath(filename_buffer_size, filename); if (temp_size == 0 || temp_size > filename_buffer_size) { // Getting the temp path failed as well; dump to current working directory as a last resort. temp_size = GetCurrentDirectory(filename_buffer_size, filename); if (temp_size == 0 || temp_size > filename_buffer_size) { // We don't really have any directory where we can store the dump, so just // write the text log (we already have a FD for that) filename[0] = L'\0'; } } } HANDLE file = INVALID_HANDLE_VALUE; if (filename[0] != L'\0') { // There is some path where we want to store our data const wchar_t tmpl[] = TEXT(C4ENGINENICK) L"-crash-YYYY-MM-DD-HH-MM-SS.dmp"; size_t path_len = wcslen(filename); if (path_len + sizeof(tmpl) / sizeof(*tmpl) > filename_buffer_size) { // Somehow the length of the required path is too long to fit in // our buffer. Don't dump anything then. filename[0] = L'\0'; } else { // Make sure the path ends in a backslash. if (filename[path_len - 1] != L'\\') { filename[path_len] = L'\\'; filename[++path_len] = L'\0'; } SYSTEMTIME st; GetSystemTime(&st); wsprintf(&filename[path_len], L"%s-crash-%04d-%02d-%02d-%02d-%02d-%02d.dmp", TEXT(C4ENGINENICK), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); } } if (filename[0] != L'\0') { file = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); // If we can't create a *new* file to dump into, don't dump at all. if (file == INVALID_HANDLE_VALUE) filename[0] = L'\0'; } // Write dump (human readable format) if (GetLogFD() != -1) SafeTextDump(pExceptionPointers, GetLogFD(), filename); if (file != INVALID_HANDLE_VALUE) { auto user_stream_info = MINIDUMP_USER_STREAM_INFORMATION(); auto user_stream = MINIDUMP_USER_STREAM(); char build_id[] = OC_BUILD_ID; if (OC_BUILD_ID[0] != '\0') { user_stream.Type = MDST_BuildId; user_stream.Buffer = build_id; user_stream.BufferSize = sizeof(build_id) - 1; // don't need the terminating NUL user_stream_info.UserStreamCount = 1; user_stream_info.UserStreamArray = &user_stream; } MINIDUMP_EXCEPTION_INFORMATION ExpParam; ExpParam.ThreadId = GetCurrentThreadId(); ExpParam.ExceptionPointers = pExceptionPointers; ExpParam.ClientPointers = true; MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file, MiniDumpNormal, &ExpParam, &user_stream_info, NULL); CloseHandle(file); } // Pass exception return EXCEPTION_EXECUTE_HANDLER; }