Subversion Repositories Games.Carmageddon

Rev

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