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