5 /* Copyright (C) 2009 Pawel Dziepak */
8 #include "libs/setjmp.h"
10 #include "manes/error.h"
12 typedef char uint64
[8];
16 _URC_FOREIGN_EXCEPTION_CAUGHT
= 1,
17 _URC_FATAL_PHASE2_ERROR
= 2,
18 _URC_FATAL_PHASE1_ERROR
= 3,
20 _URC_END_OF_STACK
= 5,
21 _URC_HANDLER_FOUND
= 6,
22 _URC_INSTALL_CONTEXT
= 7,
23 _URC_CONTINUE_UNWIND
= 8
24 } _Unwind_Reason_Code
;
27 struct _Unwind_Context
{
35 typedef void (*_Unwind_Exception_Cleanup_Fn
)(_Unwind_Reason_Code reason
, struct _Unwind_Exception
*exc
);
37 struct _Unwind_Exception
{
38 uint64 exception_class
;
39 _Unwind_Exception_Cleanup_Fn exception_cleanup
;
45 /* Personality Routine Actions */
46 typedef int _Unwind_Action
;
47 static const _Unwind_Action _UA_SEARCH_PHASE
= 1;
48 static const _Unwind_Action _UA_CLEANUP_PHASE
= 2;
49 static const _Unwind_Action _UA_HANDLER_FRAME
= 4;
50 static const _Unwind_Action _UA_FORCE_UNWIND
= 8;
53 typedef _Unwind_Reason_Code (*personality_fn
)(int version
, _Unwind_Action actions
, uint64 exception_class
,_Unwind_Exception
*ue_header
, _Unwind_Context
*context
);
54 /* Based on DWARF3 Specification */
56 /* Read unsigned little endain base 128 value */
57 unsigned int read_uleb128(char *data
, int &index
) {
58 unsigned int value
= 0;
59 unsigned char shift
= 0;
61 value
|= ((data
[index
] & 0x7f) << shift
);
64 } while(data
[index
- 1] & 0x80);
69 /* Read signed little endain base 128 value */
70 signed int read_sleb128(char *data
, int &index
) {
72 unsigned char shift
= 0;
74 value
|= ((data
[index
] & 0x7f) << shift
);
77 } while(data
[index
- 1] & 0x80);
79 unsigned int minus
= 0xffffffff & ~((1 << (shift
- 1)) - 1);
80 if (value
& (1 << (shift
- 1)))
88 unsigned int initial_location
;
89 unsigned int address_range
;
93 unsigned int personality
;
97 unsigned int get_personality(unsigned int cie
) {
99 cie
+= sizeof(unsigned int) * 2; // length and cie_id
100 for (; *(char*)cie
; cie
++); // augmentation string
102 read_uleb128((char*)cie
, i
); // code align
103 read_uleb128((char*)cie
, i
); // data align
104 unsigned int ret_index
= read_uleb128((char*)cie
, i
); // return address index
106 cie
++; // augmentation size
110 return *(unsigned int*)cie
;
115 unsigned int get_lsda(fde
*current
) {
116 unsigned int pointer
= (unsigned int)current
;
117 pointer
+= sizeof(fde
);
118 if (*(char*)pointer
== 0 || *(char*)pointer
== 4) {
120 return *(unsigned int*)pointer
;
125 return_fde
get_fde(unsigned int eip
) {
126 extern void *_eh_frame
;
127 extern void *_eh_frame_end
;
129 fde
*current
= (fde
*)&_eh_frame
;
130 unsigned int last_cie
= (unsigned int)current
;
132 while ((unsigned int)current
< (unsigned int)&_eh_frame_end
) {
133 /* do not want CIE */
134 if (current
->cie_pointer
!= (fde
*)0) {
136 if (eip
>= current
->initial_location
137 && eip
<= current
->initial_location
+ current
->address_range
) {
139 ret
.found_fde
= current
;
140 ret
.personality
= get_personality(last_cie
);
141 ret
.lsda
= get_lsda(current
);
147 last_cie
= (unsigned int)current
;
150 current
= (fde
*)((unsigned int)current
+ current
->length
+ sizeof(unsigned int));
156 /* Based on IA-64 ABI Specification */
159 struct __cxa_exception
{
160 std::type_info
*exceptionType
;
161 void (*exceptionDestructor
) (void *);
162 /* unexpected_handler unexpectedHandler;
163 terminate_handler terminateHandler;*/
164 __cxa_exception
* nextException
;
167 int handlerSwitchValue
;
168 const char *actionRecord
;
169 const char *languageSpecificData
;
173 _Unwind_Exception unwindHeader
;
176 struct __cxa_eh_globals
{
177 __cxa_exception
*caughtExceptions
;
178 unsigned int uncaughtExceptions
;
181 __cxa_eh_globals eh_globals
;
183 __cxa_eh_globals
*__cxa_get_globals(void) {
187 extern "C" void _Unwind_Resume(_Unwind_Exception ex
) {
190 struct frame_pointer
{
195 unsigned int _Unwind_GetIP(struct _Unwind_Context
*context
) {
199 unsigned int _Unwind_GetCFA(struct _Unwind_Context
*context
) {
203 unsigned int _Unwind_GetLanguageSpecificData(struct _Unwind_Context
*context
) {
204 return context
->lsda
;
207 unsigned int _Unwind_GetRegionStart(struct _Unwind_Context
*context
) {
208 return context
->proc
;
211 void *get_eh_frame();
213 extern "C" _Unwind_Reason_Code
_Unwind_RaiseException(_Unwind_Exception
*ex
) {
216 * Ask personality at each eip if there is an exception handler.
219 frame_pointer
*current_fp
;
220 personality_fn personality
;
221 _Unwind_Context context
;
222 __asm__("movl %%ebp, %%eax" : "=a" (current_fp
));
223 current_fp
= current_fp
->next
;
226 return _URC_END_OF_STACK
;
228 unsigned int return_point
= current_fp
->eip
;
230 return_fde ret
= get_fde(return_point
);
231 context
.eip
= return_point
;
232 context
.ebp
= (unsigned int)current_fp
->next
;
233 context
.proc
= ret
.found_fde
->initial_location
;
234 context
.lsda
= ret
.lsda
;
238 personality_fn personality
;
240 /* UD and what? All this code is implementation-specific */
241 cast
.val
= ret
.personality
;
242 personality
= cast
.personality
;
244 current_fp
= current_fp
->next
;
246 } while(personality(1, _UA_SEARCH_PHASE
, ex
->exception_class
, ex
, &context
) != _URC_HANDLER_FOUND
);
249 * Ask personality to perform cleanup at each eip and eventually jump to the handler.
252 _Unwind_Context handler
= context
;
253 __asm__("movl %%ebp, %%eax" : "=a" (current_fp
));
255 unsigned int return_point
= current_fp
->eip
;
257 return_fde ret
= get_fde(return_point
);
258 context
.eip
= return_point
;
259 context
.ebp
= (unsigned int)current_fp
->next
;
260 context
.proc
= ret
.found_fde
->initial_location
;
261 context
.lsda
= ret
.lsda
;
265 personality_fn personality
;
267 /* UD and what? All this code is implementation-specific */
268 cast
.val
= ret
.personality
;
269 personality
= cast
.personality
;
271 context
.eip
= return_point
;
272 context
.ebp
= (unsigned int)current_fp
->next
;
274 current_fp
= current_fp
->next
;
275 } while (context
.ebp
!= handler
.ebp
&& personality(1, _UA_CLEANUP_PHASE
, ex
->exception_class
, ex
, &context
) != _URC_FATAL_PHASE2_ERROR
);
278 personality(1, _UA_HANDLER_FRAME
, ex
->exception_class
, ex
, &handler
);
283 struct lsda_header_info
287 const unsigned char *TType;
288 const unsigned char *action_table;
289 unsigned char ttype_encoding;
290 unsigned char call_site_encoding;
295 unsigned int lpstart
;
297 unsigned int call_site_encoding
;
302 #define DW_EH_PE_omit 0xff
304 lsda_header
read_lsda_header(char *lsda
, _Unwind_Context
*context
) {
306 int start_lsda
= (int)lsda
;
307 char encoding
= *lsda
++;
310 /* if (encoding != 0xff) {
313 info
.lpstart
= _Unwind_GetRegionStart(context
);
318 if (encoding
!= 0xff) {
320 unsigned int ttype
= read_uleb128(lsda
, i
);
321 info
.ttype
= (char*)(ttype
+ (int)lsda
+ i
);
325 /* Read Call-site entries encoding */
326 info
.call_site_encoding
= *lsda
++;
328 /* Read Action table */
330 unsigned int action
= read_uleb128(lsda
, i
);
331 info
.action_table
= (char*)(action
+ (int)lsda
+ i
);
335 info
.call_site
= lsda
;
340 extern "C" _Unwind_Reason_Code
__gxx_personality_v0(int version
, _Unwind_Action actions
, uint64 exception_class
, _Unwind_Exception
*ue_header
, _Unwind_Context
*context
) {
342 return _URC_FATAL_PHASE1_ERROR
;
344 if (actions
== _UA_SEARCH_PHASE
) {
345 unsigned int lsda
= _Unwind_GetLanguageSpecificData(context
);
348 return _URC_CONTINUE_UNWIND
;
350 lsda_header hdr
= read_lsda_header((char*)lsda
, context
);
351 unsigned int ip
= _Unwind_GetIP(context
) - 5; // sizeof(call addr32) == 5
353 // we assume that call_site encoding == uleb128
355 int cs_ip
= 0, cs_len
= 0, cs_lp
= 0, cs_action
= 0;
357 /* Go through call site table (look for ip) */
358 cs_ip
= read_uleb128(hdr
.call_site
, i
) + hdr
.lpstart
;
359 cs_len
= read_uleb128(hdr
.call_site
, i
);
360 cs_lp
= read_uleb128(hdr
.call_site
, i
);
361 cs_action
= read_uleb128(hdr
.call_site
, i
) - 1;
365 __cxa_exception
*full_exception
= (__cxa_exception
*)((unsigned int)ue_header
- sizeof(__cxa_exception
) + sizeof(_Unwind_Exception
));
367 /* Go through action table (look for type to catch) */
369 int position
= cs_action
;
371 int action_id
= read_uleb128(hdr
.action_table
, position
);
375 cs_action
= position
;
376 next
= read_sleb128(hdr
.action_table
, position
);
378 std::type_info
*type
= (std::type_info
*)*(unsigned int*)((unsigned int)hdr
.ttype
- action_id
* sizeof(unsigned int));
380 if (*type
== *full_exception
->exceptionType
) {
381 /* cache collected data */
383 return _URC_HANDLER_FOUND
;
390 } while((unsigned int)&hdr
.call_site
[i
] <= (unsigned int)hdr
.action_table
);
392 return _URC_CONTINUE_UNWIND
;
394 } else if (actions
== _UA_CLEANUP_PHASE
) {
396 } else if (actions
== _UA_HANDLER_FRAME
) {
402 extern "C" void *__cxa_allocate_exception(unsigned int thrown_size
){
403 char *excp
= new char[thrown_size
+ sizeof(__cxa_exception
)];
404 memset(excp
, 0, sizeof(__cxa_exception
));
405 return (void*)((unsigned int)excp
+ sizeof(__cxa_exception
));
408 extern "C" void __cxa_throw(void *obj
, std::type_info
*tinfo
, void (*dest
) (void *)) {
409 __cxa_exception
*header
= ((__cxa_exception
*)obj
- 1);
411 header
->exceptionDestructor
= dest
;
412 header
->exceptionType
= tinfo
;
413 strncpy(header
->unwindHeader
.exception_class
, "QUARC++\0", 8);
415 __cxa_get_globals()->uncaughtExceptions
++;
417 _Unwind_RaiseException(&header
->unwindHeader
);
419 critical("unhandled exception thrown");
422 extern "C" void __cxa_begin_catch() {
425 extern "C" void __cxa_end_catch(){}