Mon Jan 30 12:51:10 CET 2006 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / exceptions-x86.c
1 /*
2  * exceptions-x86.c: exception support for x86
3  *
4  * Authors:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <signal.h>
13 #include <string.h>
14
15 #include <mono/arch/x86/x86-codegen.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/tabledefs.h>
18 #include <mono/metadata/threads.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/metadata/exception.h>
21 #include <mono/metadata/gc-internal.h>
22 #include <mono/metadata/mono-debug.h>
23
24 #include "mini.h"
25 #include "mini-x86.h"
26
27 #if defined(__FreeBSD__)
28 #include <ucontext.h>
29 #endif 
30
31 #ifdef PLATFORM_WIN32
32 static void (*restore_stack) (void *);
33
34 static MonoW32ExceptionHandler fpe_handler;
35 static MonoW32ExceptionHandler ill_handler;
36 static MonoW32ExceptionHandler segv_handler;
37
38 static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
39
40 #define W32_SEH_HANDLE_EX(_ex) \
41         if (_ex##_handler) _ex##_handler((int)sctx)
42
43 /*
44  * mono_win32_get_handle_stackoverflow (void):
45  *
46  * Returns a pointer to a method which restores the current context stack
47  * and calls handle_exceptions, when done restores the original stack.
48  */
49 static gpointer
50 mono_win32_get_handle_stackoverflow (void)
51 {
52         static guint8 *start = NULL;
53         guint8 *code;
54
55         if (start)
56                 return start;
57
58         /* restore_contect (void *sigctx) */
59         start = code = mono_global_codeman_reserve (128);
60
61         /* load context into ebx */
62         x86_mov_reg_membase (code, X86_EBX, X86_ESP, 4, 4);
63
64         /* move current stack into edi for later restore */
65         x86_mov_reg_reg (code, X86_EDI, X86_ESP, 4);
66
67         /* use the new freed stack from sigcontext */
68         x86_mov_reg_membase (code, X86_ESP, X86_EBX,  G_STRUCT_OFFSET (struct sigcontext, esp), 4);
69
70         /* get the current domain */
71         x86_call_code (code, mono_domain_get);
72
73         /* get stack overflow exception from domain object */
74         x86_mov_reg_membase (code, X86_EAX, X86_EAX, G_STRUCT_OFFSET (MonoDomain, stack_overflow_ex), 4);
75
76         /* call mono_arch_handle_exception (sctx, stack_overflow_exception_obj, FALSE) */
77         x86_push_imm (code, 0);
78         x86_push_reg (code, X86_EAX);
79         x86_push_reg (code, X86_EBX);
80         x86_call_code (code, mono_arch_handle_exception);
81
82         /* restore the SEH handler stack */
83         x86_mov_reg_reg (code, X86_ESP, X86_EDI, 4);
84
85         /* return */
86         x86_ret (code);
87
88         return start;
89 }
90
91 /* Special hack to workaround the fact that the
92  * when the SEH handler is called the stack is
93  * to small to recover.
94  *
95  * Stack walking part of this method is from mono_handle_exception
96  *
97  * The idea is simple; 
98  *  - walk the stack to free some space (64k)
99  *  - set esp to new stack location
100  *  - call mono_arch_handle_exception with stack overflow exception
101  *  - set esp to SEH handlers stack
102  *  - done
103  */
104 static void 
105 win32_handle_stack_overflow (EXCEPTION_POINTERS* ep, struct sigcontext *sctx) 
106 {
107     SYSTEM_INFO si;
108     DWORD page_size;
109         MonoDomain *domain = mono_domain_get ();
110         MonoJitInfo *ji, rji;
111         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
112         MonoLMF *lmf = jit_tls->lmf;            
113         MonoContext initial_ctx;
114         MonoContext ctx;
115         guint32 free_stack = 0;
116
117         /* convert sigcontext to MonoContext (due to reuse of stack walking helpers */
118         mono_arch_sigctx_to_monoctx (sctx, &ctx);
119         
120         /* get our os page size */
121     GetSystemInfo(&si);
122         page_size = si.dwPageSize;
123
124         /* Let's walk the stack to recover
125          * the needed stack space (if possible)
126          */
127         memset (&rji, 0, sizeof (rji));
128
129         initial_ctx = ctx;
130         free_stack = (guint8*)(MONO_CONTEXT_GET_BP (&ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
131
132         /* try to free 64kb from our stack */
133         do {
134                 MonoContext new_ctx;
135
136                 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &rji, &ctx, &new_ctx, NULL, &lmf, NULL, NULL);
137                 if (!ji) {
138                         g_warning ("Exception inside function without unwind info");
139                         g_assert_not_reached ();
140                 }
141
142                 if (ji != (gpointer)-1) {
143                         free_stack = (guint8*)(MONO_CONTEXT_GET_BP (&ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
144                 }
145
146                 /* todo: we should call abort if ji is -1 */
147                 ctx = new_ctx;
148         } while (free_stack < 64 * 1024 && ji != (gpointer) -1);
149
150         /* convert into sigcontext to be used in mono_arch_handle_exception */
151         mono_arch_monoctx_to_sigctx (&ctx, sctx);
152
153         /* todo: install new stack-guard page */
154
155         /* use the new stack and call mono_arch_handle_exception () */
156         restore_stack (sctx);
157 }
158
159 /*
160  * Unhandled Exception Filter
161  * Top-level per-process exception handler.
162  */
163 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep)
164 {
165         EXCEPTION_RECORD* er;
166         CONTEXT* ctx;
167         struct sigcontext* sctx;
168         LONG res;
169
170         res = EXCEPTION_CONTINUE_EXECUTION;
171
172         er = ep->ExceptionRecord;
173         ctx = ep->ContextRecord;
174         sctx = g_malloc(sizeof(struct sigcontext));
175
176         /* Copy Win32 context to UNIX style context */
177         sctx->eax = ctx->Eax;
178         sctx->ebx = ctx->Ebx;
179         sctx->ecx = ctx->Ecx;
180         sctx->edx = ctx->Edx;
181         sctx->ebp = ctx->Ebp;
182         sctx->esp = ctx->Esp;
183         sctx->esi = ctx->Esi;
184         sctx->edi = ctx->Edi;
185         sctx->eip = ctx->Eip;
186
187         switch (er->ExceptionCode) {
188         case EXCEPTION_STACK_OVERFLOW:
189                 win32_handle_stack_overflow (ep, sctx);
190                 break;
191         case EXCEPTION_ACCESS_VIOLATION:
192                 W32_SEH_HANDLE_EX(segv);
193                 break;
194         case EXCEPTION_ILLEGAL_INSTRUCTION:
195                 W32_SEH_HANDLE_EX(ill);
196                 break;
197         case EXCEPTION_INT_DIVIDE_BY_ZERO:
198         case EXCEPTION_INT_OVERFLOW:
199         case EXCEPTION_FLT_DIVIDE_BY_ZERO:
200         case EXCEPTION_FLT_OVERFLOW:
201         case EXCEPTION_FLT_UNDERFLOW:
202         case EXCEPTION_FLT_INEXACT_RESULT:
203                 W32_SEH_HANDLE_EX(fpe);
204                 break;
205         default:
206                 break;
207         }
208
209         /* Copy context back */
210         ctx->Eax = sctx->eax;
211         ctx->Ebx = sctx->ebx;
212         ctx->Ecx = sctx->ecx;
213         ctx->Edx = sctx->edx;
214         ctx->Ebp = sctx->ebp;
215         ctx->Esp = sctx->esp;
216         ctx->Esi = sctx->esi;
217         ctx->Edi = sctx->edi;
218         ctx->Eip = sctx->eip;
219
220         return res;
221 }
222
223 void win32_seh_init()
224 {
225         /* install restore stack helper */
226         if (!restore_stack)
227                 restore_stack = mono_win32_get_handle_stackoverflow ();
228
229         old_handler = SetUnhandledExceptionFilter(seh_handler);
230 }
231
232 void win32_seh_cleanup()
233 {
234         if (old_handler) SetUnhandledExceptionFilter(old_handler);
235 }
236
237 void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
238 {
239         switch (type) {
240         case SIGFPE:
241                 fpe_handler = handler;
242                 break;
243         case SIGILL:
244                 ill_handler = handler;
245                 break;
246         case SIGSEGV:
247                 segv_handler = handler;
248                 break;
249         default:
250                 break;
251         }
252 }
253
254 #endif /* PLATFORM_WIN32 */
255
256 /*
257  * mono_arch_get_restore_context:
258  *
259  * Returns a pointer to a method which restores a previously saved sigcontext.
260  */
261 gpointer
262 mono_arch_get_restore_context (void)
263 {
264         static guint8 *start = NULL;
265         guint8 *code;
266
267         if (start)
268                 return start;
269
270         /* restore_contect (MonoContext *ctx) */
271         /* we do not restore X86_EAX, X86_EDX */
272
273         start = code = mono_global_codeman_reserve (128);
274         
275         /* load ctx */
276         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
277
278         /* get return address, stored in EDX */
279         x86_mov_reg_membase (code, X86_EDX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, eip), 4);
280         /* restore EBX */
281         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebx), 4);
282         /* restore EDI */
283         x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, edi), 4);
284         /* restore ESI */
285         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esi), 4);
286         /* restore ESP */
287         x86_mov_reg_membase (code, X86_ESP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esp), 4);
288         /* restore EBP */
289         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebp), 4);
290
291         /* jump to the saved IP */
292         x86_jump_reg (code, X86_EDX);
293
294         return start;
295 }
296
297 /*
298  * mono_arch_get_call_filter:
299  *
300  * Returns a pointer to a method which calls an exception filter. We
301  * also use this function to call finally handlers (we pass NULL as 
302  * @exc object in this case).
303  */
304 gpointer
305 mono_arch_get_call_filter (void)
306 {
307         static guint8* start;
308         static int inited = 0;
309         guint8 *code;
310
311         if (inited)
312                 return start;
313
314         inited = 1;
315         /* call_filter (MonoContext *ctx, unsigned long eip) */
316         start = code = mono_global_codeman_reserve (64);
317
318         x86_push_reg (code, X86_EBP);
319         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
320         x86_push_reg (code, X86_EBX);
321         x86_push_reg (code, X86_EDI);
322         x86_push_reg (code, X86_ESI);
323
324         /* load ctx */
325         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
326         /* load eip */
327         x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
328         /* save EBP */
329         x86_push_reg (code, X86_EBP);
330
331         /* set new EBP */
332         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebp), 4);
333         /* restore registers used by global register allocation (EBX & ESI) */
334         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebx), 4);
335         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esi), 4);
336         x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, edi), 4);
337
338         /* call the handler */
339         x86_call_reg (code, X86_ECX);
340
341         /* restore EBP */
342         x86_pop_reg (code, X86_EBP);
343
344         /* restore saved regs */
345         x86_pop_reg (code, X86_ESI);
346         x86_pop_reg (code, X86_EDI);
347         x86_pop_reg (code, X86_EBX);
348         x86_leave (code);
349         x86_ret (code);
350
351         g_assert ((code - start) < 64);
352         return start;
353 }
354
355 static void
356 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
357                  unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
358                  unsigned long eip,  unsigned long esp, gboolean rethrow)
359 {
360         static void (*restore_context) (MonoContext *);
361         MonoContext ctx;
362
363         if (!restore_context)
364                 restore_context = mono_arch_get_restore_context ();
365
366         /* Pop argument and return address */
367         ctx.esp = esp + (2 * sizeof (gpointer));
368         ctx.eip = eip;
369         ctx.ebp = ebp;
370         ctx.edi = edi;
371         ctx.esi = esi;
372         ctx.ebx = ebx;
373         ctx.edx = edx;
374         ctx.ecx = ecx;
375         ctx.eax = eax;
376
377         if (mono_debugger_throw_exception ((gpointer)(eip - 5), (gpointer)esp, exc)) {
378                 /*
379                  * The debugger wants us to stop on the `throw' instruction.
380                  * By the time we get here, it already inserted a breakpoint on
381                  * eip - 5 (which is the address of the call).
382                  */
383                 ctx.eip = eip - 5;
384                 ctx.esp = esp + sizeof (gpointer);
385                 restore_context (&ctx);
386                 g_assert_not_reached ();
387         }
388
389         /* adjust eip so that it point into the call instruction */
390         ctx.eip -= 1;
391
392         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
393                 MonoException *mono_ex = (MonoException*)exc;
394                 if (!rethrow)
395                         mono_ex->stack_trace = NULL;
396         }
397         mono_handle_exception (&ctx, exc, (gpointer)eip, FALSE);
398         restore_context (&ctx);
399
400         g_assert_not_reached ();
401 }
402
403 static guint8*
404 get_throw_exception (gboolean rethrow)
405 {
406         guint8 *start, *code;
407
408         start = code = mono_global_codeman_reserve (64);
409
410         x86_push_reg (code, X86_ESP);
411         x86_push_membase (code, X86_ESP, 4); /* IP */
412         x86_push_membase (code, X86_ESP, 12); /* exception */
413         x86_push_reg (code, X86_EBP);
414         x86_push_reg (code, X86_EDI);
415         x86_push_reg (code, X86_ESI);
416         x86_push_reg (code, X86_EBX);
417         x86_push_reg (code, X86_EDX);
418         x86_push_reg (code, X86_ECX);
419         x86_push_reg (code, X86_EAX);
420         x86_call_code (code, throw_exception);
421         /* we should never reach this breakpoint */
422         x86_breakpoint (code);
423
424         g_assert ((code - start) < 64);
425
426         return start;
427 }
428
429 /**
430  * mono_arch_get_throw_exception:
431  *
432  * Returns a function pointer which can be used to raise 
433  * exceptions. The returned function has the following 
434  * signature: void (*func) (MonoException *exc); 
435  * For example to raise an arithmetic exception you can use:
436  *
437  * x86_push_imm (code, mono_get_exception_arithmetic ()); 
438  * x86_call_code (code, arch_get_throw_exception ()); 
439  *
440  */
441 gpointer 
442 mono_arch_get_throw_exception (void)
443 {
444         static guint8 *start;
445         static int inited = 0;
446
447         if (inited)
448                 return start;
449
450         start = get_throw_exception (FALSE);
451
452         inited = 1;
453
454         return start;
455 }
456
457 gpointer 
458 mono_arch_get_rethrow_exception (void)
459 {
460         static guint8 *start;
461         static int inited = 0;
462
463         if (inited)
464                 return start;
465
466         start = get_throw_exception (TRUE);
467
468         inited = 1;
469
470         return start;
471 }
472
473 /**
474  * mono_arch_get_throw_exception_by_name:
475  *
476  * Returns a function pointer which can be used to raise 
477  * corlib exceptions. The returned function has the following 
478  * signature: void (*func) (gpointer ip, char *exc_name); 
479  * For example to raise an arithmetic exception you can use:
480  *
481  * x86_push_imm (code, "ArithmeticException"); 
482  * x86_push_imm (code, <IP>)
483  * x86_jump_code (code, arch_get_throw_exception_by_name ()); 
484  *
485  */
486 gpointer 
487 mono_arch_get_throw_exception_by_name (void)
488 {
489         static guint8* start;
490         static int inited = 0;
491         guint8 *code;
492
493         if (inited)
494                 return start;
495
496         inited = 1;
497         code = start = mono_global_codeman_reserve (32);
498
499         x86_push_membase (code, X86_ESP, 4); /* exception name */
500         x86_push_imm (code, "System");
501         x86_push_imm (code, mono_defaults.exception_class->image);
502         x86_call_code (code, mono_exception_from_name);
503         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
504         /* save the newly create object (overwrite exception name)*/
505         x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
506         x86_jump_code (code, mono_arch_get_throw_exception ());
507
508         g_assert ((code - start) < 32);
509
510         return start;
511 }
512
513 /**
514  * mono_arch_get_throw_corlib_exception:
515  *
516  * Returns a function pointer which can be used to raise 
517  * corlib exceptions. The returned function has the following 
518  * signature: void (*func) (guint32 ex_token, guint32 offset); 
519  * Here, offset is the offset which needs to be substracted from the caller IP 
520  * to get the IP of the throw. Passing the offset has the advantage that it 
521  * needs no relocations in the caller.
522  */
523 gpointer 
524 mono_arch_get_throw_corlib_exception (void)
525 {
526         static guint8* start;
527         static int inited = 0;
528         guint8 *code;
529
530         if (inited)
531                 return start;
532
533         inited = 1;
534         code = start = mono_global_codeman_reserve (64);
535
536         x86_push_membase (code, X86_ESP, 4); /* token */
537         x86_push_imm (code, mono_defaults.exception_class->image);
538         x86_call_code (code, mono_exception_from_token);
539         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
540         /* Compute caller ip */
541         x86_pop_reg (code, X86_ECX);
542         /* Pop token */
543         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
544         x86_pop_reg (code, X86_EDX);
545         x86_alu_reg_reg (code, X86_SUB, X86_ECX, X86_EDX);
546         /* Push exception object */
547         x86_push_reg (code, X86_EAX);
548         /* Push throw IP */
549         x86_push_reg (code, X86_ECX);
550         x86_jump_code (code, mono_arch_get_throw_exception ());
551
552         g_assert ((code - start) < 64);
553
554         return start;
555 }
556
557 /* mono_arch_find_jit_info:
558  *
559  * This function is used to gather information from @ctx. It return the 
560  * MonoJitInfo of the corresponding function, unwinds one stack frame and
561  * stores the resulting context into @new_ctx. It also stores a string 
562  * describing the stack location into @trace (if not NULL), and modifies
563  * the @lmf if necessary. @native_offset return the IP offset from the 
564  * start of the function or -1 if that info is not available.
565  */
566 MonoJitInfo *
567 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
568                          MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
569                          gboolean *managed)
570 {
571         MonoJitInfo *ji;
572         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
573
574         /* Avoid costly table lookup during stack overflow */
575         if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
576                 ji = prev_ji;
577         else
578                 ji = mono_jit_info_table_find (domain, ip);
579
580         if (managed)
581                 *managed = FALSE;
582
583         if (ji != NULL) {
584                 int offset;
585
586                 *new_ctx = *ctx;
587
588                 if (managed)
589                         if (!ji->method->wrapper_type)
590                                 *managed = TRUE;
591
592                 /*
593                  * Some managed methods like pinvoke wrappers might have save_lmf set.
594                  * In this case, register save/restore code is not generated by the 
595                  * JIT, so we have to restore callee saved registers from the lmf.
596                  */
597                 if (ji->method->save_lmf) {
598                         /* 
599                          * We only need to do this if the exception was raised in managed
600                          * code, since otherwise the lmf was already popped of the stack.
601                          */
602                         if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
603                                 new_ctx->esi = (*lmf)->esi;
604                                 new_ctx->edi = (*lmf)->edi;
605                                 new_ctx->ebx = (*lmf)->ebx;
606                         }
607                 }
608                 else {
609                         offset = -1;
610                         /* restore caller saved registers */
611                         if (ji->used_regs & X86_EBX_MASK) {
612                                 new_ctx->ebx = *((int *)ctx->ebp + offset);
613                                 offset--;
614                         }
615                         if (ji->used_regs & X86_EDI_MASK) {
616                                 new_ctx->edi = *((int *)ctx->ebp + offset);
617                                 offset--;
618                         }
619                         if (ji->used_regs & X86_ESI_MASK) {
620                                 new_ctx->esi = *((int *)ctx->ebp + offset);
621                         }
622                 }
623
624                 if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
625                         /* remove any unused lmf */
626                         *lmf = (*lmf)->previous_lmf;
627                 }
628
629                 /* Pop EBP and the return address */
630                 new_ctx->esp = ctx->ebp + (2 * sizeof (gpointer));
631                 /* we substract 1, so that the IP points into the call instruction */
632                 new_ctx->eip = *((int *)ctx->ebp + 1) - 1;
633                 new_ctx->ebp = *((int *)ctx->ebp);
634
635                 /* Pop arguments off the stack */
636                 {
637                         MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (ji->method)->param_count + 1);
638
639                         guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (ji->method), mono_method_signature (ji->method)->param_count, arg_info);
640                         new_ctx->esp += stack_to_pop;
641                 }
642
643                 return ji;
644         } else if (*lmf) {
645                 
646                 *new_ctx = *ctx;
647
648                 if (!(*lmf)->method)
649                         return (gpointer)-1;
650
651                 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
652                 } else {
653                         memset (res, 0, sizeof (MonoJitInfo));
654                         res->method = (*lmf)->method;
655                 }
656
657                 new_ctx->esi = (*lmf)->esi;
658                 new_ctx->edi = (*lmf)->edi;
659                 new_ctx->ebx = (*lmf)->ebx;
660                 new_ctx->ebp = (*lmf)->ebp;
661                 new_ctx->eip = (*lmf)->eip;
662                 /* the lmf is always stored on the stack, so the following
663                  * expression points to a stack location which can be used as ESP */
664                 new_ctx->esp = (unsigned long)&((*lmf)->eip);
665
666                 *lmf = (*lmf)->previous_lmf;
667
668                 return ji ? ji : res;
669         }
670
671         return NULL;
672 }
673
674 #ifdef __sun
675 #define REG_EAX EAX
676 #define REG_EBX EBX
677 #define REG_ECX ECX
678 #define REG_EDX EDX
679 #define REG_EBP EBP
680 #define REG_ESP ESP
681 #define REG_ESI ESI
682 #define REG_EDI EDI
683 #define REG_EIP EIP
684 #endif
685
686 void
687 mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
688 {
689 #ifdef MONO_ARCH_USE_SIGACTION
690         ucontext_t *ctx = (ucontext_t*)sigctx;
691         
692 #if defined(__FreeBSD__)
693         mctx->eax = ctx->uc_mcontext.mc_eax;
694         mctx->ebx = ctx->uc_mcontext.mc_ebx;
695         mctx->ecx = ctx->uc_mcontext.mc_ecx;
696         mctx->edx = ctx->uc_mcontext.mc_edx;
697         mctx->ebp = ctx->uc_mcontext.mc_ebp;
698         mctx->esp = ctx->uc_mcontext.mc_esp;
699         mctx->esi = ctx->uc_mcontext.mc_esi;
700         mctx->edi = ctx->uc_mcontext.mc_edi;
701         mctx->eip = ctx->uc_mcontext.mc_eip;
702 #else
703         mctx->eax = ctx->uc_mcontext.gregs [REG_EAX];
704         mctx->ebx = ctx->uc_mcontext.gregs [REG_EBX];
705         mctx->ecx = ctx->uc_mcontext.gregs [REG_ECX];
706         mctx->edx = ctx->uc_mcontext.gregs [REG_EDX];
707         mctx->ebp = ctx->uc_mcontext.gregs [REG_EBP];
708         mctx->esp = ctx->uc_mcontext.gregs [REG_ESP];
709         mctx->esi = ctx->uc_mcontext.gregs [REG_ESI];
710         mctx->edi = ctx->uc_mcontext.gregs [REG_EDI];
711         mctx->eip = ctx->uc_mcontext.gregs [REG_EIP];
712 #endif
713 #else   
714         struct sigcontext *ctx = (struct sigcontext *)sigctx;
715
716         mctx->eax = ctx->SC_EAX;
717         mctx->ebx = ctx->SC_EBX;
718         mctx->ecx = ctx->SC_ECX;
719         mctx->edx = ctx->SC_EDX;
720         mctx->ebp = ctx->SC_EBP;
721         mctx->esp = ctx->SC_ESP;
722         mctx->esi = ctx->SC_ESI;
723         mctx->edi = ctx->SC_EDI;
724         mctx->eip = ctx->SC_EIP;
725 #endif
726 }
727
728 void
729 mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
730 {
731 #ifdef MONO_ARCH_USE_SIGACTION
732         ucontext_t *ctx = (ucontext_t*)sigctx;
733
734 #if defined(__FreeBSD__)
735         ctx->uc_mcontext.mc_eax = mctx->eax;
736         ctx->uc_mcontext.mc_ebx = mctx->ebx;
737         ctx->uc_mcontext.mc_ecx = mctx->ecx;
738         ctx->uc_mcontext.mc_edx = mctx->edx;
739         ctx->uc_mcontext.mc_ebp  = mctx->ebp;
740         ctx->uc_mcontext.mc_esp = mctx->esp;
741         ctx->uc_mcontext.mc_esi = mctx->esi;
742         ctx->uc_mcontext.mc_edi = mctx->edi;
743         ctx->uc_mcontext.mc_eip = mctx->eip;
744
745 #else
746         ctx->uc_mcontext.gregs [REG_EAX] = mctx->eax;
747         ctx->uc_mcontext.gregs [REG_EBX] = mctx->ebx;
748         ctx->uc_mcontext.gregs [REG_ECX] = mctx->ecx;
749         ctx->uc_mcontext.gregs [REG_EDX] = mctx->edx;
750         ctx->uc_mcontext.gregs [REG_EBP] = mctx->ebp;
751         ctx->uc_mcontext.gregs [REG_ESP] = mctx->esp;
752         ctx->uc_mcontext.gregs [REG_ESI] = mctx->esi;
753         ctx->uc_mcontext.gregs [REG_EDI] = mctx->edi;
754         ctx->uc_mcontext.gregs [REG_EIP] = mctx->eip;
755 #endif
756 #else
757         struct sigcontext *ctx = (struct sigcontext *)sigctx;
758
759         ctx->SC_EAX = mctx->eax;
760         ctx->SC_EBX = mctx->ebx;
761         ctx->SC_ECX = mctx->ecx;
762         ctx->SC_EDX = mctx->edx;
763         ctx->SC_EBP = mctx->ebp;
764         ctx->SC_ESP = mctx->esp;
765         ctx->SC_ESI = mctx->esi;
766         ctx->SC_EDI = mctx->edi;
767         ctx->SC_EIP = mctx->eip;
768 #endif
769 }       
770
771 gpointer
772 mono_arch_ip_from_context (void *sigctx)
773 {
774 #ifdef MONO_ARCH_USE_SIGACTION
775         ucontext_t *ctx = (ucontext_t*)sigctx;
776 #if defined(__FreeBSD__)
777         return (gpointer)ctx->uc_mcontext.mc_eip;
778 #else
779         return (gpointer)ctx->uc_mcontext.gregs [REG_EIP];
780 #endif
781 #else
782         struct sigcontext *ctx = sigctx;
783         return (gpointer)ctx->SC_EIP;
784 #endif  
785 }
786
787 gboolean
788 mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
789 {
790         MonoContext mctx;
791
792         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
793
794         mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, test_only);
795
796         mono_arch_monoctx_to_sigctx (&mctx, sigctx);
797
798         return TRUE;
799 }