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