1 #include <Exception.d>
2 #include <__oo2c.h>
3
4 #include <setjmp.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #if HAVE_BACKTRACE_SYMBOLS
9 # include <execinfo.h>
10 #endif
11
12 #define EXCEPTION_EXIT_CODE 126
13
14 static Exception__ThreadState local_state;
15
Exception__ExceptionDesc_INIT(Exception__Exception e,Object__String msg)16 void Exception__ExceptionDesc_INIT(Exception__Exception e,
17 Object__String msg) {
18 e->msg = msg;
19 e->backtraceSize = -1;
20 }
21
Exception__Current()22 Exception__Exception Exception__Current() {
23 return Exception__GetThreadState()->currentException;
24 }
25
26 #define SIZE_BUFFER 1024
Exception__Abort(Exception__Exception e)27 void Exception__Abort(Exception__Exception e) {
28 RT0__Struct td = OOC_TYPE_TAG(e);
29 Object__String msg =
30 OOC_TBCALL(OOC_TBPROC_ADR(td,Exception__ExceptionDesc_GetMessage),
31 Exception__ExceptionDesc_GetMessage)(e);
32 /* if the type name ends with "Desc", then drop the last 4 characters */
33 int len = strlen((char*)td->name);
34 if ((len >= 4) && (strcmp((char*)td->name + (len-4), "Desc") == 0)) {
35 len -= 4;
36 }
37 fprintf(stderr, "## Exception: %s.%.*s", td->module->name, len, td->name);
38
39 if (msg) {
40 char buffer[SIZE_BUFFER];
41 int i, j = 4;
42 _TBP_Object__StringDesc_CharAt charAt =
43 OOC_TBPROC_ADR(OOC_TYPE_TAG(msg), Object__StringDesc_CharAt);
44
45 strcpy(buffer, "\n## ");
46 for (i=0; i != msg->length; i++) {
47 OOC_INT32 c = OOC_TBCALL(charAt,Object__StringDesc_CharAt)(msg,i);
48 buffer[j] = (c>0xff) ? '?' : (char)c;
49 j++;
50 if (j == SIZE_BUFFER) {
51 fwrite(buffer, sizeof(char), SIZE_BUFFER, stderr);
52 j = 0;
53 }
54 }
55 fwrite(buffer, sizeof(char), j, stderr);
56 }
57
58 (void)fprintf(stderr, "\n\n");
59 Exception__ExceptionDesc_WriteBacktrace(e);
60 exit(EXCEPTION_EXIT_CODE);
61 }
62
Exception__ActivateContext()63 void Exception__ActivateContext() {
64 Exception__ContextPtr cs = Exception__GetThreadState()->contextStack;
65
66 if (cs) {
67 longjmp(*(jmp_buf*)cs->jmpbuf, 1);
68 } else {
69 Exception__Abort(Exception__Current());
70 }
71 }
72
Exception__Raise(Exception__Exception e)73 void Exception__Raise(Exception__Exception e) {
74 if (e->backtraceSize < 0) {
75 #if HAVE_BACKTRACE_SYMBOLS
76 e->backtraceSize = backtrace(e->backtrace, Exception__maxBacktraceSize);
77 #else
78 e->backtraceSize = 0;
79 #endif
80 }
81
82 Exception__GetThreadState()->currentException = e;
83 Exception__ActivateContext();
84 }
85
Exception__FatalError(Object__String msg)86 void Exception__FatalError(Object__String msg) {
87 Exception__Exception e =
88 RT0__NewObject(OOC_TYPE_DESCR(Exception,ExceptionDesc));
89
90 Exception__ExceptionDesc_INIT(e, msg);
91 #if HAVE_BACKTRACE_SYMBOLS
92 e->backtraceSize = backtrace(e->backtrace, Exception__maxBacktraceSize);
93 #else
94 e->backtraceSize = 0;
95 #endif
96 Exception__Abort(e);
97 }
98
Exception__Clear()99 void Exception__Clear() {
100 Exception__GetThreadState()->currentException = NULL;
101 }
102
Exception__PushContext(struct Exception__Context * context,OOC_PTR jmpbuf)103 void Exception__PushContext(struct Exception__Context *context,
104 OOC_PTR jmpbuf) {
105 Exception__ThreadStatePtr ts = Exception__GetThreadState();
106
107 context->next = ts->contextStack;
108 context->jmpbuf = jmpbuf;
109 ts->contextStack = context;
110 }
111
Exception__PopContext(OOC_INT32 n)112 void Exception__PopContext(OOC_INT32 n) {
113 Exception__ThreadStatePtr ts = Exception__GetThreadState();
114
115 while (n > 0) {
116 ts->contextStack = ts->contextStack->next;
117 n--;
118 }
119 }
120
Exception__ExceptionDesc_WriteBacktrace(Exception__Exception e)121 void Exception__ExceptionDesc_WriteBacktrace(Exception__Exception e) {
122 #if HAVE_BACKTRACE_SYMBOLS
123 int i;
124 char** names;
125
126 if (e->backtraceSize >= 0) {
127 names = backtrace_symbols(e->backtrace, e->backtraceSize);
128 for (i=0; i<e->backtraceSize; i++) {
129 (void)fprintf(stderr, "%d: %s\n", i, names[i]);
130 }
131 free(names);
132 }
133 #endif
134 }
135
Exception__ExceptionDesc_GetMessage(Exception__Exception e)136 Object__String Exception__ExceptionDesc_GetMessage(Exception__Exception e) {
137 return e->msg;
138 }
139
140 #define B 256
Exception__ExceptionDesc_Name(Exception__Exception e)141 Object__String8 Exception__ExceptionDesc_Name(Exception__Exception e) {
142 RT0__Struct td = OOC_TYPE_TAG(e);
143 Object__String msg =
144 OOC_TBCALL(OOC_TBPROC_ADR(td,Exception__ExceptionDesc_GetMessage),
145 Exception__ExceptionDesc_GetMessage)(e);
146 char b[B];
147
148 /* if the type name ends with "Desc", then drop the last 4 characters */
149 int len = strlen((char*)td->name);
150 if ((len >= 4) && (strcmp((char*)td->name + (len-4), "Desc") == 0)) {
151 len -= 4;
152 }
153 /* this may cause a buffer overflow for _very_ long module/type names */
154 sprintf(b, "%s.%.*s", td->module->name, len, td->name);
155 return Object__NewLatin1Region((OOC_CHAR8*)b, B, 0, strlen(b));
156 }
157
158
Exception__ParseErrorDesc_INIT(Exception__ParseError e,Object__String msg,OOC_INT32 offset)159 void Exception__ParseErrorDesc_INIT(Exception__ParseError e,
160 Object__String msg, OOC_INT32 offset) {
161 Exception__ExceptionDesc_INIT((Exception__Exception)e, msg);
162 e->offset = offset;
163 }
164
Exception__InitThreadState(Exception__ThreadState * ts)165 void Exception__InitThreadState(Exception__ThreadState *ts) {
166 ts->contextStack = NULL;
167 ts->currentException = NULL;
168 }
169
local_GetThreadState()170 static Exception__ThreadStatePtr local_GetThreadState() {
171 return &local_state;
172 }
173
OOC_Exception_init(void)174 void OOC_Exception_init(void) {
175 Exception__InitThreadState(&local_state);
176 Exception__GetThreadState = local_GetThreadState;
177 }
178
OOC_Exception_destroy(void)179 void OOC_Exception_destroy(void) {
180 /* FIXME... if we ever to module unloading */
181 }
182