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 __APPLE__ // Pierre-Marie Baty -- added compile guard
4
 
18 pmbaty 5
#include "harness/config.h"
1 pmbaty 6
#include "harness/os.h"
7
#include <assert.h>
8
#include <dirent.h>
9
#include <err.h>
10
#include <errno.h>
11
#include <execinfo.h>
12
#include <inttypes.h>
13
#include <libgen.h>
14
#include <limits.h>
15
#include <mach-o/dyld.h>
16
#include <signal.h>
17
#include <stdbool.h>
18
#include <stdint.h>
19
#include <stdio.h>
20
#include <stdlib.h>
21
#include <string.h>
22
#include <sys/sysctl.h>
23
#include <sys/types.h>
24
#include <time.h>
25
#include <unistd.h>
26
 
27
#define ARRAY_SIZE(A) (sizeof(A) / sizeof(A[0]))
28
 
29
static int stack_nbr = 0;
30
static char _program_name[1024];
31
#define MAX_STACK_FRAMES 64
32
static void* stack_traces[MAX_STACK_FRAMES];
33
static char name_buf[4096];
34
 
35
// Resolve symbol name and source location given the path to the executable and an address
36
int addr2line(char const* const program_name, intptr_t slide, void const* const addr) {
14 pmbaty 37
    static char addr2line_cmd[MAXPATHLEN]; // Pierre-Marie Baty -- use the heap instead
1 pmbaty 38
 
39
    /* have addr2line map the address to the related line in the code */
14 pmbaty 40
    sprintf(addr2line_cmd, "atos -s %" PRIxPTR " -o \"%s\" %p", slide, program_name, addr); // Pierre-Marie Baty -- enclosed program_name within quotes to support pathnames with spaces
1 pmbaty 41
 
42
    // printf("addr2line command: %s\n", addr2line_cmd);
43
 
44
    fprintf(stderr, "%d: ", stack_nbr++);
45
    return system(addr2line_cmd);
46
}
47
 
48
static void print_stack_trace(void) {
49
    int i, trace_size = 0;
50
    char** messages = (char**)NULL;
51
    intptr_t slide;
52
 
53
    trace_size = backtrace(stack_traces, MAX_STACK_FRAMES);
54
    messages = backtrace_symbols(stack_traces, trace_size);
55
    slide = _dyld_get_image_vmaddr_slide(0);
56
 
57
    fputs("\nStack trace:\n", stderr);
58
 
59
    /* skip the first couple stack frames (as they are this function and
60
     our handler) and also skip the last frame as it's (always?) junk. */
61
    for (i = 3; i < (trace_size - 1); i++) {
62
 
63
        // seem to get a duplicate frame right where the error happens
64
        if (stack_traces[i] == stack_traces[i - 1]) {
65
            continue;
66
        }
67
        if (addr2line(_program_name, slide, stack_traces[i]) != 0) {
68
            printf("  error determining line # for: %s\n", messages[i]);
69
        }
70
    }
71
    if (messages) {
72
        free(messages);
73
    }
74
}
75
 
76
void signal_handler(int sig, siginfo_t* siginfo, void* context) {
77
    (void)context;
78
    fputs("\n******************\n", stderr);
79
 
80
    switch (sig) {
81
    case SIGSEGV:
82
        fputs("Caught SIGSEGV\n", stderr);
83
        break;
84
    case SIGINT:
85
        fputs("Caught SIGINT\n", stderr);
86
        break;
87
    case SIGFPE:
88
        switch (siginfo->si_code) {
89
        case FPE_INTDIV:
90
            fputs("Caught SIGFPE: FPE_INTDIV\n", stderr);
91
            break;
92
        case FPE_INTOVF:
93
            fputs("Caught SIGFPE: FPE_INTOVF\n", stderr);
94
            break;
95
        case FPE_FLTDIV:
96
            fputs("Caught SIGFPE: FPE_FLTDIV\n", stderr);
97
            break;
98
        case FPE_FLTOVF:
99
            fputs("Caught SIGFPE: FPE_FLTOVF\n", stderr);
100
            break;
101
        case FPE_FLTUND:
102
            fputs("Caught SIGFPE: FPE_FLTUND\n", stderr);
103
            break;
104
        case FPE_FLTRES:
105
            fputs("Caught SIGFPE: FPE_FLTRES\n", stderr);
106
            break;
107
        case FPE_FLTINV:
108
            fputs("Caught SIGFPE: FPE_FLTINV\n", stderr);
109
            break;
110
        case FPE_FLTSUB:
111
            fputs("Caught SIGFPE: FPE_FLTSUB\n", stderr);
112
            break;
113
        default:
114
            fputs("Caught SIGFPE: Arithmetic Exception\n", stderr);
115
            break;
116
        }
117
        break;
118
    case SIGILL:
119
        switch (siginfo->si_code) {
120
        case ILL_ILLOPC:
121
            fputs("Caught SIGILL: ILL_ILLOPC\n", stderr);
122
            break;
123
        case ILL_ILLOPN:
124
            fputs("Caught SIGILL: ILL_ILLOPN\n", stderr);
125
            break;
126
        case ILL_ILLADR:
127
            fputs("Caught SIGILL: ILL_ILLADR\n", stderr);
128
            break;
129
        case ILL_ILLTRP:
130
            fputs("Caught SIGILL: ILL_ILLTRP\n", stderr);
131
            break;
132
        case ILL_PRVOPC:
133
            fputs("Caught SIGILL: ILL_PRVOPC\n", stderr);
134
            break;
135
        case ILL_PRVREG:
136
            fputs("Caught SIGILL: ILL_PRVREG\n", stderr);
137
            break;
138
        case ILL_COPROC:
139
            fputs("Caught SIGILL: ILL_COPROC\n", stderr);
140
            break;
141
        case ILL_BADSTK:
142
            fputs("Caught SIGILL: ILL_BADSTK\n", stderr);
143
            break;
144
        default:
145
            fputs("Caught SIGILL: Illegal Instruction\n", stderr);
146
            break;
147
        }
148
        break;
149
    case SIGTERM:
150
        fputs("Caught SIGTERM\n", stderr);
151
        break;
152
    case SIGABRT:
153
        fputs("Caught SIGABRT\n", stderr);
154
        break;
155
    default:
156
        break;
157
    }
158
    fputs("******************\n", stderr);
159
    print_stack_trace();
160
    exit(1);
161
}
162
 
163
static uint8_t alternate_stack[SIGSTKSZ];
164
 
165
void resolve_full_path(char* path, const char* argv0) {
166
    if (argv0[0] == '/') { // run with absolute path
167
        strcpy(path, argv0);
18 pmbaty 168
    } else { // run with relative path
1 pmbaty 169
        if (NULL == getcwd(path, PATH_MAX)) {
170
            perror("getcwd error");
171
            return;
172
        }
173
        strcat(path, "/");
174
        strcat(path, argv0);
175
    }
176
}
177
 
178
void OS_InstallSignalHandler(char* program_name) {
179
 
180
    resolve_full_path(_program_name, program_name);
181
 
182
    /* setup alternate stack */
183
    {
184
        stack_t ss = {};
185
        /* malloc is usually used here, I'm not 100% sure my static allocation
186
         is valid but it seems to work just fine. */
187
        ss.ss_sp = (void*)alternate_stack;
188
        ss.ss_size = SIGSTKSZ;
189
        ss.ss_flags = 0;
190
 
191
        if (sigaltstack(&ss, NULL) != 0) {
192
            err(1, "sigaltstack");
193
        }
194
    }
195
 
196
    /* register our signal handlers */
197
    {
198
        struct sigaction sig_action = {};
199
        sig_action.sa_sigaction = signal_handler;
200
        sigemptyset(&sig_action.sa_mask);
201
 
202
        sig_action.sa_flags = SA_SIGINFO;
203
 
204
        if (sigaction(SIGSEGV, &sig_action, NULL) != 0) {
205
            err(1, "sigaction");
206
        }
207
        if (sigaction(SIGFPE, &sig_action, NULL) != 0) {
208
            err(1, "sigaction");
209
        }
210
        if (sigaction(SIGINT, &sig_action, NULL) != 0) {
211
            err(1, "sigaction");
212
        }
213
        if (sigaction(SIGILL, &sig_action, NULL) != 0) {
214
            err(1, "sigaction");
215
        }
216
        if (sigaction(SIGTERM, &sig_action, NULL) != 0) {
217
            err(1, "sigaction");
218
        }
219
        if (sigaction(SIGABRT, &sig_action, NULL) != 0) {
220
            err(1, "sigaction");
221
        }
222
    }
223
}
224
 
225
FILE* OS_fopen(const char* pathname, const char* mode) {
11 pmbaty 226
    FILE* f;
227
 
228
    f = fopen(pathname, mode);
18 pmbaty 229
    if (harness_game_config.verbose) {
230
        if (f == NULL) {
231
            fprintf(stderr, "Failed to open \"%s\" (%s)\n", pathname, strerror(errno));
232
        }
11 pmbaty 233
    }
234
 
235
    return f;
1 pmbaty 236
}
237
 
238
size_t OS_ConsoleReadPassword(char* pBuffer, size_t pBufferLen) {
239
    // FIXME: unsafe implementation (echos the password)
240
    pBuffer[0] = '\0';
241
    fgets(pBuffer, pBufferLen, stdin);
242
    return strlen(pBuffer);
243
}
244
 
245
char* OS_Dirname(const char* path) {
246
    strcpy(name_buf, path);
247
    return dirname(name_buf);
248
}
249
 
250
char* OS_Basename(const char* path) {
251
    strcpy(name_buf, path);
252
    return basename(name_buf);
253
}
254
 
255
#endif // __APPLE__