aboutsummaryrefslogtreecommitdiff
path: root/libs/installer_fomod_plus/installer/lib/CrashHandler.cpp
blob: 98ed1f32a794f1d58154e30b5e640800caf6b816 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include "CrashHandler.h"
#include <iostream>

#ifdef _WIN32
#include <windows.h>
#include <dbghelp.h>
#include <sstream>
#include <fstream>

LPTOP_LEVEL_EXCEPTION_FILTER CrashHandler::previousFilter = nullptr;
PVOID CrashHandler::vectoredHandler = nullptr;
#endif

void CrashHandler::initialize() {
#ifdef _WIN32
    std::cout << "CrashHandler initializing..." << std::endl;
    vectoredHandler = AddVectoredExceptionHandler(1, vectoredExceptionHandler);
    previousFilter = SetUnhandledExceptionFilter(unhandledExceptionFilter);
    std::cout << "CrashHandler initialized successfully" << std::endl;
#else
    // No-op on Linux — Windows crash handler not needed.
#endif
}

void CrashHandler::cleanup() {
#ifdef _WIN32
    if (vectoredHandler) {
        RemoveVectoredExceptionHandler(vectoredHandler);
        vectoredHandler = nullptr;
    }
    if (previousFilter) {
        SetUnhandledExceptionFilter(previousFilter);
        previousFilter = nullptr;
    }
#endif
}

#ifdef _WIN32
LONG WINAPI CrashHandler::vectoredExceptionHandler(EXCEPTION_POINTERS* exceptionInfo) {
    // Log all exceptions but only create dumps for serious ones
    std::cout << "Exception caught: 0x" << std::hex << exceptionInfo->ExceptionRecord->ExceptionCode << std::endl;
    
    // Only create dumps for serious crashes, not benign exceptions
    if (exceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
        exceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW ||
        exceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) {
        
        // For stack overflow, we need to handle it on a different thread with its own stack
        if (exceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
            // Create a new thread to handle the crash dump since our stack is corrupted
            HANDLE dumpThread = CreateThread(nullptr, 0, [](LPVOID param) -> DWORD {
                auto* exceptionInfo = static_cast<EXCEPTION_POINTERS*>(param);
                logCrashInfo(exceptionInfo);
                
                HANDLE file = CreateFileA("fomod_plus_stack_overflow.dmp", GENERIC_WRITE, 0, nullptr,
                                         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
                
                if (file != INVALID_HANDLE_VALUE) {
                    MINIDUMP_EXCEPTION_INFORMATION dumpInfo = {0};
                    dumpInfo.ThreadId = GetCurrentThreadId();
                    dumpInfo.ExceptionPointers = exceptionInfo;
                    dumpInfo.ClientPointers = FALSE;
                    
                    MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file,
                                     MiniDumpNormal, &dumpInfo, nullptr, nullptr);
                    CloseHandle(file);
                    
                    std::cout << "Stack overflow crash dump written to fomod_plus_stack_overflow.dmp" << std::endl;
                }
                return 0;
            }, exceptionInfo, 0, nullptr);
            
            if (dumpThread) {
                WaitForSingleObject(dumpThread, 5000); // Wait up to 5 seconds
                CloseHandle(dumpThread);
            }
        } else {
            logCrashInfo(exceptionInfo);
            
            // Generate minidump
            HANDLE file = CreateFileA("fomod_plus_crash.dmp", GENERIC_WRITE, 0, nullptr,
                                     CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
            
            if (file != INVALID_HANDLE_VALUE) {
                MINIDUMP_EXCEPTION_INFORMATION dumpInfo = {0};
                dumpInfo.ThreadId = GetCurrentThreadId();
                dumpInfo.ExceptionPointers = exceptionInfo;
                dumpInfo.ClientPointers = FALSE;
                
                MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), file,
                                 MiniDumpNormal, &dumpInfo, nullptr, nullptr);
                CloseHandle(file);
                
                std::cout << "Crash dump written to fomod_plus_crash.dmp" << std::endl;
            }
        }
    }
    
    return EXCEPTION_CONTINUE_SEARCH;  // Let other handlers process it
}

LONG WINAPI CrashHandler::unhandledExceptionFilter(EXCEPTION_POINTERS* exceptionInfo) {
    logCrashInfo(exceptionInfo);
    return EXCEPTION_EXECUTE_HANDLER;
}

void CrashHandler::logCrashInfo(const EXCEPTION_POINTERS* exceptionInfo) {
    std::ostringstream oss;
    oss << "FOMOD PLUS CRASH DETECTED!" << std::endl;
    oss << "Exception Code: 0x" << std::hex << exceptionInfo->ExceptionRecord->ExceptionCode << std::endl;
    oss << "Exception Address: 0x" << std::hex << exceptionInfo->ExceptionRecord->ExceptionAddress << std::endl;
    
    // Write to stdout immediately
    std::cout << oss.str() << std::endl;
    
    // Also write to crash log file
    std::ofstream crashLog("fomod_plus_crash.log", std::ios::app);
    if (crashLog.is_open()) {
        crashLog << oss.str() << std::endl;
    }
}
#endif