5 /* Copyright (C) 2009 Pawel Dziepak */
8 //#include "manes/error.h"
12 asm("cli\nhlt"::"a"(0xdeadbeef));
16 typedef char uint64
[8];
17 typedef unsigned int cpu_word
;
19 int strncpy(char*,const char*,int);
20 int memset(void*,int,int);
24 _URC_FOREIGN_EXCEPTION_CAUGHT
= 1,
25 _URC_FATAL_PHASE2_ERROR
= 2,
26 _URC_FATAL_PHASE1_ERROR
= 3,
28 _URC_END_OF_STACK
= 5,
29 _URC_HANDLER_FOUND
= 6,
30 _URC_INSTALL_CONTEXT
= 7,
31 _URC_CONTINUE_UNWIND
= 8
32 } _Unwind_Reason_Code
;
35 struct _Unwind_Context
{
48 typedef void (*_Unwind_Exception_Cleanup_Fn
)(_Unwind_Reason_Code reason
, struct _Unwind_Exception
*exc
);
50 struct _Unwind_Exception
{
51 uint64 exception_class
;
52 _Unwind_Exception_Cleanup_Fn exception_cleanup
;
58 /* Personality Routine Actions */
59 typedef int _Unwind_Action
;
60 static const _Unwind_Action _UA_SEARCH_PHASE
= 1;
61 static const _Unwind_Action _UA_CLEANUP_PHASE
= 2;
62 static const _Unwind_Action _UA_HANDLER_FRAME
= 4;
63 static const _Unwind_Action _UA_FORCE_UNWIND
= 8;
65 void jump_to(cpu_word eax
, cpu_word edx
, cpu_word ebp
, cpu_word eip
) {
66 /* TODO: This routine should also set old esp value! */
67 asm("movl %%ecx, %%ebp\n" \
69 "ret" ::"a"(eax
), "d"(edx
), "c"(ebp
), "S" (eip
));
72 typedef _Unwind_Reason_Code (*personality_fn
)(int version
, _Unwind_Action actions
, uint64 exception_class
,_Unwind_Exception
*ue_header
, _Unwind_Context
*context
);
73 /* Based on DWARF3 Specification */
75 /* Read unsigned little endain base 128 value */
76 cpu_word
read_uleb128(unsigned char *data
, int &index
) {
78 unsigned char shift
= 0;
80 value
|= ((data
[index
] & 0x7f) << shift
);
83 } while(data
[index
- 1] & 0x80);
88 /* Read signed little endain base 128 value */
89 signed int read_sleb128(unsigned char *data
, int &index
) {
91 unsigned char shift
= 0;
93 value
|= ((data
[index
] & 0x7f) << shift
);
96 } while(data
[index
- 1] & 0x80);
98 cpu_word minus
= 0xffffffff & ~((1 << (shift
- 1)) - 1);
99 if (value
& (1 << (shift
- 1)))
107 cpu_word initial_location
;
108 cpu_word address_range
;
112 cpu_word personality
;
116 cpu_word
get_personality(cpu_word cie
) {
117 cie
+= sizeof(cpu_word
) * 2; // length and cie_id
118 for (; *reinterpret_cast<unsigned char*>(cie
); cie
++); // augmentation string
120 read_uleb128(reinterpret_cast<unsigned char*>(cie
), i
); // code align
121 read_uleb128(reinterpret_cast<unsigned char*>(cie
), i
); // data align
122 read_uleb128(reinterpret_cast<unsigned char*>(cie
), i
); // return address index
124 cie
++; // augmentation size
126 if (! *reinterpret_cast<char*>(cie
)) {
128 return *reinterpret_cast<cpu_word
*>(cie
);
133 cpu_word
get_lsda(fde
*current
) {
134 cpu_word pointer
= reinterpret_cast<cpu_word
>(current
);
135 pointer
+= sizeof(fde
);
136 if (*reinterpret_cast<char*>(pointer
) == 0 || *reinterpret_cast<char*>(pointer
) == 4) {
138 return *reinterpret_cast<cpu_word
*>(pointer
);
143 return_fde
get_fde(cpu_word eip
) {
144 extern void *_eh_frame
;
145 extern void *_eh_frame_end
;
147 fde
*current
= reinterpret_cast<fde
*>(&_eh_frame
);
149 while ((cpu_word
)current
< (cpu_word
)&_eh_frame_end
) {
150 /* do not want CIE */
151 if (current
->cie_pointer
!= (fde
*)0) {
153 if (eip
>= current
->initial_location
154 && eip
<= current
->initial_location
+ current
->address_range
) {
156 ret
.found_fde
= current
;
157 cpu_word cie
= (cpu_word
)current
+ sizeof(unsigned int) - (cpu_word
)current
->cie_pointer
;
158 ret
.personality
= get_personality(cie
);
159 ret
.lsda
= get_lsda(current
);
165 current
= reinterpret_cast<fde
*>(reinterpret_cast<cpu_word
>(current
) + current
->length
+ sizeof(cpu_word
));
169 /* Based on IA-64 ABI Specification */
172 struct __cxa_exception
{
173 std::type_info
*exceptionType
;
174 void (*exceptionDestructor
) (void *);
175 /* unexpected_handler unexpectedHandler;
176 terminate_handler terminateHandler;*/
177 __cxa_exception
* nextException
;
180 int handlerSwitchValue
;
181 const char *actionRecord
;
182 const char *languageSpecificData
;
186 _Unwind_Exception unwindHeader
;
189 struct __cxa_eh_globals
{
190 __cxa_exception
*caughtExceptions
;
191 cpu_word uncaughtExceptions
;
194 __cxa_eh_globals eh_globals
;
196 __cxa_eh_globals
*__cxa_get_globals(void) {
200 extern "C" void _Unwind_Resume(_Unwind_Exception ex
) {
203 struct frame_pointer
{
208 cpu_word
_Unwind_GetIP(struct _Unwind_Context
*context
) {
212 cpu_word
_Unwind_GetCFA(struct _Unwind_Context
*context
) {
216 cpu_word
_Unwind_GetLanguageSpecificData(struct _Unwind_Context
*context
) {
217 return context
->lsda
;
220 cpu_word
_Unwind_GetRegionStart(struct _Unwind_Context
*context
) {
221 return context
->proc
;
224 void _Unwind_SetGR(_Unwind_Context
*context
, int index
, cpu_word new_value
) {
226 context
->eax
= new_value
;
228 context
->edx
= new_value
;
231 void _Unwind_SetIP(_Unwind_Context
*context
, cpu_word new_value
) {
232 context
->landing_pad
= new_value
;
236 void *get_eh_frame();
238 void InstallContext(_Unwind_Context
*context
) {
239 /* TODO: Set old esp and register values (other than eax and edx)! */
240 jump_to(context
->eax
, context
->edx
, context
->ebp
, context
->landing_pad
);
243 extern "C" _Unwind_Reason_Code
_Unwind_RaiseException(_Unwind_Exception
*ex
) {
246 * Ask personality at each eip if there is an exception handler.
249 frame_pointer
*current_fp
;
250 personality_fn personality
;
251 _Unwind_Context context
;
252 __asm__("movl %%ebp, %%eax" : "=a" (current_fp
));
253 current_fp
= current_fp
->next
;
256 return _URC_END_OF_STACK
;
258 cpu_word return_point
= current_fp
->eip
;
260 return_fde ret
= get_fde(return_point
);
261 context
.eip
= return_point
;
262 context
.ebp
= reinterpret_cast<cpu_word
>(current_fp
->next
);
263 context
.proc
= ret
.found_fde
->initial_location
;
264 context
.lsda
= ret
.lsda
;
268 personality_fn personality
;
270 /* UD and what? All this code is implementation-specific */
271 cast
.val
= ret
.personality
;
272 personality
= cast
.personality
;
274 current_fp
= current_fp
->next
;
276 } while(personality(1, _UA_SEARCH_PHASE
, ex
->exception_class
, ex
, &context
) != _URC_HANDLER_FOUND
);
279 * Ask personality to perform cleanup at each eip and eventually jump to the handler.
282 _Unwind_Context handler
= context
;
283 __asm__("movl %%ebp, %%eax" : "=a" (current_fp
));
285 cpu_word return_point
= current_fp
->eip
;
287 return_fde ret
= get_fde(return_point
);
288 context
.eip
= return_point
;
289 context
.ebp
= reinterpret_cast<cpu_word
>(current_fp
->next
);
290 context
.proc
= ret
.found_fde
->initial_location
;
291 context
.lsda
= ret
.lsda
;
295 personality_fn personality
;
297 /* UD and what? All this code is implementation-specific */
298 cast
.val
= ret
.personality
;
299 personality
= cast
.personality
;
301 context
.eip
= return_point
;
302 context
.ebp
= reinterpret_cast<cpu_word
>(current_fp
->next
);
304 current_fp
= current_fp
->next
;
305 } while (context
.ebp
!= handler
.ebp
&& personality(1, _UA_CLEANUP_PHASE
, ex
->exception_class
, ex
, &context
) != _URC_FATAL_PHASE2_ERROR
);
308 personality(1, _UA_HANDLER_FRAME
, ex
->exception_class
, ex
, &handler
);
313 struct lsda_header_info
317 const unsigned char *TType;
318 const unsigned char *action_table;
319 unsigned char ttype_encoding;
320 unsigned char call_site_encoding;
326 unsigned char *ttype
;
327 cpu_word call_site_encoding
;
328 unsigned char *action_table
;
329 unsigned char *call_site
;
332 #define DW_EH_PE_omit 0xff
334 lsda_header
read_lsda_header(unsigned char *lsda
, _Unwind_Context
*context
) {
336 unsigned char encoding
= *lsda
++;
339 /* if (encoding != 0xff) {
342 info
.lpstart
= _Unwind_GetRegionStart(context
);
347 if (encoding
!= 0xff) {
349 cpu_word ttype
= read_uleb128(lsda
, i
);
350 info
.ttype
= reinterpret_cast<unsigned char*>(ttype
+ reinterpret_cast<cpu_word
>(lsda
) + i
);
354 /* Read Call-site entries encoding */
355 info
.call_site_encoding
= *lsda
++;
357 /* Read Action table */
359 cpu_word action
= read_uleb128(lsda
, i
);
360 info
.action_table
= reinterpret_cast<unsigned char*>(action
+ reinterpret_cast<cpu_word
>(lsda
) + i
);
364 info
.call_site
= lsda
;
369 extern "C" _Unwind_Reason_Code
__gxx_personality_v0(int version
, _Unwind_Action actions
, uint64 exception_class
, _Unwind_Exception
*ue_header
, _Unwind_Context
*context
) {
371 return _URC_FATAL_PHASE1_ERROR
;
373 if (actions
== _UA_SEARCH_PHASE
) {
374 cpu_word lsda
= _Unwind_GetLanguageSpecificData(context
);
377 return _URC_CONTINUE_UNWIND
;
379 lsda_header hdr
= read_lsda_header(reinterpret_cast<unsigned char*>(lsda
), context
);
380 cpu_word ip
= _Unwind_GetIP(context
) - 5; // sizeof(call addr32) == 5
382 // we assume that call_site encoding == uleb128
384 cpu_word cs_ip
= 0, cs_len
= 0, cs_lp
= 0, cs_action
= 0;
386 /* Go through call site table (look for ip) */
387 cs_ip
= read_uleb128(hdr
.call_site
, i
) + hdr
.lpstart
;
388 cs_len
= read_uleb128(hdr
.call_site
, i
);
389 cs_lp
= read_uleb128(hdr
.call_site
, i
);
390 cs_action
= read_uleb128(hdr
.call_site
, i
) - 1;
394 __cxa_exception
*full_exception
= (__cxa_exception
*)((cpu_word
)ue_header
- sizeof(__cxa_exception
) + sizeof(_Unwind_Exception
));
396 /* Go through action table (look for type to catch) */
398 int position
= cs_action
;
400 int action_id
= read_uleb128(hdr
.action_table
, position
);
404 cs_action
= position
;
405 next
= read_sleb128(hdr
.action_table
, position
);
407 std::type_info
*type
= *reinterpret_cast<std::type_info
**>(reinterpret_cast<cpu_word
>(hdr
.ttype
) - action_id
* sizeof(cpu_word
));
409 if (*type
== *full_exception
->exceptionType
) {
410 /* cache collected data */
412 /* F*ck cleanup phase, jump now */
413 _Unwind_SetGR(context
, 0, reinterpret_cast<cpu_word
>(ue_header
));
414 _Unwind_SetGR(context
, 1, action_id
);
415 _Unwind_SetIP(context
, hdr
.lpstart
+ cs_lp
);
416 InstallContext(context
);
418 return _URC_HANDLER_FOUND
;
425 } while(reinterpret_cast<cpu_word
>(&hdr
.call_site
[i
]) <= reinterpret_cast<cpu_word
>(hdr
.action_table
));
427 return _URC_CONTINUE_UNWIND
;
429 } else if (actions
== _UA_CLEANUP_PHASE
) {
431 } else if (actions
== _UA_HANDLER_FRAME
) {
437 extern "C" void *__cxa_allocate_exception(cpu_word thrown_size
){
438 char *excp
= new char[thrown_size
+ sizeof(__cxa_exception
)];
439 memset(excp
, 0, sizeof(__cxa_exception
));
440 return reinterpret_cast<void*>(reinterpret_cast<cpu_word
>(excp
) + sizeof(__cxa_exception
));
443 extern "C" void __cxa_throw(void *obj
, std::type_info
*tinfo
, void (*dest
) (void *)) {
444 __cxa_exception
*header
= reinterpret_cast<__cxa_exception
*>(obj
) - 1;
446 header
->exceptionDestructor
= dest
;
447 header
->exceptionType
= tinfo
;
448 strncpy(header
->unwindHeader
.exception_class
, "QUARC++\0", 8);
450 __cxa_get_globals()->uncaughtExceptions
++;
452 _Unwind_RaiseException(&header
->unwindHeader
);
454 //critical("unhandled exception thrown");
455 asm("cli\nhlt"::"a"(0xdeadbeef));
458 extern "C" void __cxa_begin_catch() {
461 extern "C" void __cxa_end_catch(){}