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