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