Subversion Repositories Games.Carmageddon

Rev

Rev 14 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
// Based on https://gist.github.com/jvranish/4441299
2
 
3
#ifdef _WIN32 // Pierre-Marie Baty -- added compile guard
4
 
5
// this has to be first
6
#include <windows.h>
7
 
8
#include <imagehlp.h>
9
 
18 pmbaty 10
#include "harness/config.h"
1 pmbaty 11
#include "harness/os.h"
12
 
13
#include <assert.h>
14
#include <direct.h>
15
#include <errno.h>
16
#include <limits.h>
17
#include <signal.h>
18
#include <stdbool.h>
19
#include <stdint.h>
20
#include <stdio.h>
21
#include <stdlib.h>
22
#include <string.h>
23
 
24
#ifdef _WIN64
25
#define Esp Rsp
26
#define Eip Rip
27
#define Ebp Rbp
28
#endif
29
 
30
void dr_dprintf(char* fmt_string, ...);
31
 
32
static int stack_nbr = 0;
11 pmbaty 33
static char windows_program_name[1024];
1 pmbaty 34
 
35
static char dirname_buf[_MAX_DIR];
36
static char fname_buf[_MAX_FNAME];
37
 
11 pmbaty 38
static int addr2line(char const* const program_name, void const* const addr) {
1 pmbaty 39
    char addr2line_cmd[512] = { 0 };
40
 
41
    sprintf(addr2line_cmd, "addr2line -f -p -e %.256s %p", program_name, addr);
42
 
43
    fprintf(stderr, "%d: ", stack_nbr++);
44
    return system(addr2line_cmd);
45
}
46
 
11 pmbaty 47
static void print_stacktrace(CONTEXT* context) {
14 pmbaty 48
#if 0 // Pierre-Marie Baty -- looks like this doesn't build right away on Windows
1 pmbaty 49
    SymInitialize(GetCurrentProcess(), 0, true);
50
 
51
    STACKFRAME frame = { 0 };
52
 
53
    /* setup initial stack frame */
54
    frame.AddrPC.Offset = context->Eip;
55
    frame.AddrPC.Mode = AddrModeFlat;
56
    frame.AddrStack.Offset = context->Esp;
57
    frame.AddrStack.Mode = AddrModeFlat;
58
    frame.AddrFrame.Offset = context->Ebp;
59
    frame.AddrFrame.Mode = AddrModeFlat;
60
 
61
    while (StackWalk(IMAGE_FILE_MACHINE_I386,
62
        GetCurrentProcess(),
63
        GetCurrentThread(),
64
        &frame,
65
        context,
66
        0,
67
        SymFunctionTableAccess,
68
        SymGetModuleBase,
69
        0)) {
11 pmbaty 70
        addr2line(windows_program_name, (void*)frame.AddrPC.Offset);
1 pmbaty 71
    }
72
 
73
    SymCleanup(GetCurrentProcess());
14 pmbaty 74
#endif // 0
1 pmbaty 75
}
76
 
11 pmbaty 77
static LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS* ExceptionInfo) {
1 pmbaty 78
    switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
79
    case EXCEPTION_ACCESS_VIOLATION:
80
        fputs("Error: EXCEPTION_ACCESS_VIOLATION\n", stderr);
81
        break;
82
    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
83
        fputs("Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr);
84
        break;
85
    case EXCEPTION_BREAKPOINT:
86
        fputs("Error: EXCEPTION_BREAKPOINT\n", stderr);
87
        break;
88
    case EXCEPTION_DATATYPE_MISALIGNMENT:
89
        fputs("Error: EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr);
90
        break;
91
    case EXCEPTION_FLT_DENORMAL_OPERAND:
92
        fputs("Error: EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr);
93
        break;
94
    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
95
        fputs("Error: EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr);
96
        break;
97
    case EXCEPTION_FLT_INEXACT_RESULT:
98
        fputs("Error: EXCEPTION_FLT_INEXACT_RESULT\n", stderr);
99
        break;
100
    case EXCEPTION_FLT_INVALID_OPERATION:
101
        fputs("Error: EXCEPTION_FLT_INVALID_OPERATION\n", stderr);
102
        break;
103
    case EXCEPTION_FLT_OVERFLOW:
104
        fputs("Error: EXCEPTION_FLT_OVERFLOW\n", stderr);
105
        break;
106
    case EXCEPTION_FLT_STACK_CHECK:
107
        fputs("Error: EXCEPTION_FLT_STACK_CHECK\n", stderr);
108
        break;
109
    case EXCEPTION_FLT_UNDERFLOW:
110
        fputs("Error: EXCEPTION_FLT_UNDERFLOW\n", stderr);
111
        break;
112
    case EXCEPTION_ILLEGAL_INSTRUCTION:
113
        fputs("Error: EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr);
114
        break;
115
    case EXCEPTION_IN_PAGE_ERROR:
116
        fputs("Error: EXCEPTION_IN_PAGE_ERROR\n", stderr);
117
        break;
118
    case EXCEPTION_INT_DIVIDE_BY_ZERO:
119
        fputs("Error: EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr);
120
        break;
121
    case EXCEPTION_INT_OVERFLOW:
122
        fputs("Error: EXCEPTION_INT_OVERFLOW\n", stderr);
123
        break;
124
    case EXCEPTION_INVALID_DISPOSITION:
125
        fputs("Error: EXCEPTION_INVALID_DISPOSITION\n", stderr);
126
        break;
127
    case EXCEPTION_NONCONTINUABLE_EXCEPTION:
128
        fputs("Error: EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr);
129
        break;
130
    case EXCEPTION_PRIV_INSTRUCTION:
131
        fputs("Error: EXCEPTION_PRIV_INSTRUCTION\n", stderr);
132
        break;
133
    case EXCEPTION_SINGLE_STEP:
134
        fputs("Error: EXCEPTION_SINGLE_STEP\n", stderr);
135
        break;
136
    case EXCEPTION_STACK_OVERFLOW:
137
        fputs("Error: EXCEPTION_STACK_OVERFLOW\n", stderr);
138
        break;
139
    default:
140
        fputs("Error: Unrecognized Exception\n", stderr);
141
        break;
142
    }
143
    fflush(stderr);
144
    /* If this is a stack overflow then we can't walk the stack, so just show
145
      where the error happened */
146
    if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) {
147
        print_stacktrace(ExceptionInfo->ContextRecord);
148
    } else {
11 pmbaty 149
        addr2line(windows_program_name, (void*)ExceptionInfo->ContextRecord->Eip);
1 pmbaty 150
    }
151
 
152
    return EXCEPTION_EXECUTE_HANDLER;
153
}
154
 
155
void OS_InstallSignalHandler(char* program_name) {
11 pmbaty 156
    strcpy(windows_program_name, program_name);
1 pmbaty 157
    SetUnhandledExceptionFilter(windows_exception_handler);
158
}
159
 
160
FILE* OS_fopen(const char* pathname, const char* mode) {
161
    FILE* f;
162
    errno_t err;
163
 
164
    f = NULL;
165
    err = fopen_s(&f, pathname, mode);
18 pmbaty 166
    if (harness_game_config.verbose) {
167
        if (err != 0) {
168
            fprintf(stderr, "Failed to open \"%s\" (%s)\n", pathname, strerror(err));
169
        }
1 pmbaty 170
    }
171
 
172
    return f;
173
}
174
 
175
size_t OS_ConsoleReadPassword(char* pBuffer, size_t pBufferLen) {
176
    // FIXME: unsafe implementation (echos the password)
177
    pBuffer[0] = '\0';
178
    fgets(pBuffer, pBufferLen, stdin);
179
    return strlen(pBuffer);
180
}
181
 
182
char* OS_Dirname(const char* path) {
183
    _splitpath(path, NULL, dirname_buf, NULL, NULL);
184
    return dirname_buf;
185
}
186
 
187
char* OS_Basename(const char* path) {
188
    _splitpath(path, NULL, NULL, fname_buf, NULL);
189
    return fname_buf;
190
}
191
 
192
#endif // _WIN32