2007-07-22 Zoltan Varga <vargaz@gmail.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 #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         g_free (sctx);
217
218         return res;
219 }
220
221 void win32_seh_init()
222 {
223         /* install restore stack helper */
224         if (!restore_stack)
225                 restore_stack = mono_win32_get_handle_stackoverflow ();
226
227         old_handler = SetUnhandledExceptionFilter(seh_handler);
228 }
229
230 void win32_seh_cleanup()
231 {
232         if (old_handler) SetUnhandledExceptionFilter(old_handler);
233 }
234
235 void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
236 {
237         switch (type) {
238         case SIGFPE:
239                 fpe_handler = handler;
240                 break;
241         case SIGILL:
242                 ill_handler = handler;
243                 break;
244         case SIGSEGV:
245                 segv_handler = handler;
246                 break;
247         default:
248                 break;
249         }
250 }
251
252 #endif /* PLATFORM_WIN32 */
253
254 /*
255  * mono_arch_get_restore_context:
256  *
257  * Returns a pointer to a method which restores a previously saved sigcontext.
258  */
259 gpointer
260 mono_arch_get_restore_context (void)
261 {
262         static guint8 *start = NULL;
263         guint8 *code;
264
265         if (start)
266                 return start;
267
268         /* restore_contect (MonoContext *ctx) */
269         /* we do not restore X86_EAX, X86_EDX */
270
271         start = code = mono_global_codeman_reserve (128);
272         
273         /* load ctx */
274         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
275
276         /* get return address, stored in EDX */
277         x86_mov_reg_membase (code, X86_EDX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, eip), 4);
278         /* restore EBX */
279         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebx), 4);
280         /* restore EDI */
281         x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, edi), 4);
282         /* restore ESI */
283         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esi), 4);
284         /* restore ESP */
285         x86_mov_reg_membase (code, X86_ESP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esp), 4);
286         /* restore EBP */
287         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebp), 4);
288
289         /* jump to the saved IP */
290         x86_jump_reg (code, X86_EDX);
291
292         return start;
293 }
294
295 /*
296  * mono_arch_get_call_filter:
297  *
298  * Returns a pointer to a method which calls an exception filter. We
299  * also use this function to call finally handlers (we pass NULL as 
300  * @exc object in this case).
301  */
302 gpointer
303 mono_arch_get_call_filter (void)
304 {
305         static guint8* start;
306         static int inited = 0;
307         guint8 *code;
308
309         if (inited)
310                 return start;
311
312         inited = 1;
313         /* call_filter (MonoContext *ctx, unsigned long eip) */
314         start = code = mono_global_codeman_reserve (64);
315
316         x86_push_reg (code, X86_EBP);
317         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
318         x86_push_reg (code, X86_EBX);
319         x86_push_reg (code, X86_EDI);
320         x86_push_reg (code, X86_ESI);
321
322         /* load ctx */
323         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
324         /* load eip */
325         x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
326         /* save EBP */
327         x86_push_reg (code, X86_EBP);
328
329         /* set new EBP */
330         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebp), 4);
331         /* restore registers used by global register allocation (EBX & ESI) */
332         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebx), 4);
333         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esi), 4);
334         x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, edi), 4);
335
336         /* call the handler */
337         x86_call_reg (code, X86_ECX);
338
339         /* restore EBP */
340         x86_pop_reg (code, X86_EBP);
341
342         /* restore saved regs */
343         x86_pop_reg (code, X86_ESI);
344         x86_pop_reg (code, X86_EDI);
345         x86_pop_reg (code, X86_EBX);
346         x86_leave (code);
347         x86_ret (code);
348
349         g_assert ((code - start) < 64);
350         return start;
351 }
352
353 static void
354 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
355                  unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
356                  unsigned long eip,  unsigned long esp, gboolean rethrow)
357 {
358         static void (*restore_context) (MonoContext *);
359         MonoContext ctx;
360
361         if (!restore_context)
362                 restore_context = mono_arch_get_restore_context ();
363
364         /* Pop argument and return address */
365         ctx.esp = esp + (2 * sizeof (gpointer));
366         ctx.eip = eip;
367         ctx.ebp = ebp;
368         ctx.edi = edi;
369         ctx.esi = esi;
370         ctx.ebx = ebx;
371         ctx.edx = edx;
372         ctx.ecx = ecx;
373         ctx.eax = eax;
374
375         if (mono_debugger_throw_exception ((gpointer)(eip - 5), (gpointer)esp, exc)) {
376                 /*
377                  * The debugger wants us to stop on the `throw' instruction.
378                  * By the time we get here, it already inserted a breakpoint on
379                  * eip - 5 (which is the address of the call).
380                  */
381                 ctx.eip = eip - 5;
382                 ctx.esp = esp + sizeof (gpointer);
383                 restore_context (&ctx);
384                 g_assert_not_reached ();
385         }
386
387         /* adjust eip so that it point into the call instruction */
388         ctx.eip -= 1;
389
390         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
391                 MonoException *mono_ex = (MonoException*)exc;
392                 if (!rethrow)
393                         mono_ex->stack_trace = NULL;
394         }
395         mono_handle_exception (&ctx, exc, (gpointer)eip, FALSE);
396         restore_context (&ctx);
397
398         g_assert_not_reached ();
399 }
400
401 static guint8*
402 get_throw_exception (gboolean rethrow)
403 {
404         guint8 *start, *code;
405
406         start = code = mono_global_codeman_reserve (64);
407
408         x86_push_reg (code, X86_ESP);
409         x86_push_membase (code, X86_ESP, 4); /* IP */
410         x86_push_membase (code, X86_ESP, 12); /* exception */
411         x86_push_reg (code, X86_EBP);
412         x86_push_reg (code, X86_EDI);
413         x86_push_reg (code, X86_ESI);
414         x86_push_reg (code, X86_EBX);
415         x86_push_reg (code, X86_EDX);
416         x86_push_reg (code, X86_ECX);
417         x86_push_reg (code, X86_EAX);
418         x86_call_code (code, throw_exception);
419         /* we should never reach this breakpoint */
420         x86_breakpoint (code);
421
422         g_assert ((code - start) < 64);
423
424         return start;
425 }
426
427 /**
428  * mono_arch_get_throw_exception:
429  *
430  * Returns a function pointer which can be used to raise 
431  * exceptions. The returned function has the following 
432  * signature: void (*func) (MonoException *exc); 
433  * For example to raise an arithmetic exception you can use:
434  *
435  * x86_push_imm (code, mono_get_exception_arithmetic ()); 
436  * x86_call_code (code, arch_get_throw_exception ()); 
437  *
438  */
439 gpointer 
440 mono_arch_get_throw_exception (void)
441 {
442         static guint8 *start;
443         static int inited = 0;
444
445         if (inited)
446                 return start;
447
448         start = get_throw_exception (FALSE);
449
450         inited = 1;
451
452         return start;
453 }
454
455 gpointer 
456 mono_arch_get_rethrow_exception (void)
457 {
458         static guint8 *start;
459         static int inited = 0;
460
461         if (inited)
462                 return start;
463
464         start = get_throw_exception (TRUE);
465
466         inited = 1;
467
468         return start;
469 }
470
471 /**
472  * mono_arch_get_throw_exception_by_name:
473  *
474  * Returns a function pointer which can be used to raise 
475  * corlib exceptions. The returned function has the following 
476  * signature: void (*func) (gpointer ip, char *exc_name); 
477  * For example to raise an arithmetic exception you can use:
478  *
479  * x86_push_imm (code, "ArithmeticException"); 
480  * x86_push_imm (code, <IP>)
481  * x86_jump_code (code, arch_get_throw_exception_by_name ()); 
482  *
483  */
484 gpointer 
485 mono_arch_get_throw_exception_by_name (void)
486 {
487         static guint8* start;
488         static int inited = 0;
489         guint8 *code;
490
491         if (inited)
492                 return start;
493
494         inited = 1;
495         code = start = mono_global_codeman_reserve (32);
496
497         x86_push_membase (code, X86_ESP, 4); /* exception name */
498         x86_push_imm (code, "System");
499         x86_push_imm (code, mono_defaults.exception_class->image);
500         x86_call_code (code, mono_exception_from_name);
501         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
502         /* save the newly create object (overwrite exception name)*/
503         x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
504         x86_jump_code (code, mono_arch_get_throw_exception ());
505
506         g_assert ((code - start) < 32);
507
508         return start;
509 }
510
511 /**
512  * mono_arch_get_throw_corlib_exception:
513  *
514  * Returns a function pointer which can be used to raise 
515  * corlib exceptions. The returned function has the following 
516  * signature: void (*func) (guint32 ex_token, guint32 offset); 
517  * Here, offset is the offset which needs to be substracted from the caller IP 
518  * to get the IP of the throw. Passing the offset has the advantage that it 
519  * needs no relocations in the caller.
520  */
521 gpointer 
522 mono_arch_get_throw_corlib_exception (void)
523 {
524         static guint8* start;
525         static int inited = 0;
526         guint8 *code;
527
528         if (inited)
529                 return start;
530
531         inited = 1;
532         code = start = mono_global_codeman_reserve (64);
533
534         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4); /* token */
535         x86_alu_reg_imm (code, X86_ADD, X86_EAX, MONO_TOKEN_TYPE_DEF);
536         x86_push_reg (code, X86_EAX);
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 = (gpointer)(((guint32)(*lmf)->previous_lmf) & ~1);
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 ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
649                 } else {
650                         if (!(*lmf)->method)
651                                 /* Top LMF entry */
652                                 return (gpointer)-1;
653                         /* Trampoline lmf frame */
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
664                 /* Check if we are in a trampoline LMF frame */
665                 if ((guint32)((*lmf)->previous_lmf) & 1) {
666                         /* lmf->esp is set by the trampoline code */
667                         new_ctx->esp = (*lmf)->esp;
668
669                         /* Pop arguments off the stack */
670                         {
671                                 MonoMethod *method = (*lmf)->method;
672                                 MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (method)->param_count + 1);
673
674                                 guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (method), mono_method_signature (method)->param_count, arg_info);
675                                 new_ctx->esp += stack_to_pop;
676                         }
677                 }
678                 else
679                         /* the lmf is always stored on the stack, so the following
680                          * expression points to a stack location which can be used as ESP */
681                         new_ctx->esp = (unsigned long)&((*lmf)->eip);
682
683                 *lmf = (gpointer)(((guint32)(*lmf)->previous_lmf) & ~1);
684
685                 return ji ? ji : res;
686         }
687
688         return NULL;
689 }
690
691 #ifdef __sun
692 #define REG_EAX EAX
693 #define REG_EBX EBX
694 #define REG_ECX ECX
695 #define REG_EDX EDX
696 #define REG_EBP EBP
697 #define REG_ESP ESP
698 #define REG_ESI ESI
699 #define REG_EDI EDI
700 #define REG_EIP EIP
701 #endif
702
703 void
704 mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
705 {
706 #ifdef MONO_ARCH_USE_SIGACTION
707         ucontext_t *ctx = (ucontext_t*)sigctx;
708         
709         mctx->eax = UCONTEXT_REG_EAX (ctx);
710         mctx->ebx = UCONTEXT_REG_EBX (ctx);
711         mctx->ecx = UCONTEXT_REG_ECX (ctx);
712         mctx->edx = UCONTEXT_REG_EDX (ctx);
713         mctx->ebp = UCONTEXT_REG_EBP (ctx);
714         mctx->esp = UCONTEXT_REG_ESP (ctx);
715         mctx->esi = UCONTEXT_REG_ESI (ctx);
716         mctx->edi = UCONTEXT_REG_EDI (ctx);
717         mctx->eip = UCONTEXT_REG_EIP (ctx);
718 #else   
719         struct sigcontext *ctx = (struct sigcontext *)sigctx;
720
721         mctx->eax = ctx->SC_EAX;
722         mctx->ebx = ctx->SC_EBX;
723         mctx->ecx = ctx->SC_ECX;
724         mctx->edx = ctx->SC_EDX;
725         mctx->ebp = ctx->SC_EBP;
726         mctx->esp = ctx->SC_ESP;
727         mctx->esi = ctx->SC_ESI;
728         mctx->edi = ctx->SC_EDI;
729         mctx->eip = ctx->SC_EIP;
730 #endif
731 }
732
733 void
734 mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
735 {
736 #ifdef MONO_ARCH_USE_SIGACTION
737         ucontext_t *ctx = (ucontext_t*)sigctx;
738
739         UCONTEXT_REG_EAX (ctx) = mctx->eax;
740         UCONTEXT_REG_EBX (ctx) = mctx->ebx;
741         UCONTEXT_REG_ECX (ctx) = mctx->ecx;
742         UCONTEXT_REG_EDX (ctx) = mctx->edx;
743         UCONTEXT_REG_EBP (ctx) = mctx->ebp;
744         UCONTEXT_REG_ESP (ctx) = mctx->esp;
745         UCONTEXT_REG_ESI (ctx) = mctx->esi;
746         UCONTEXT_REG_EDI (ctx) = mctx->edi;
747         UCONTEXT_REG_EIP (ctx) = mctx->eip;
748 #else
749         struct sigcontext *ctx = (struct sigcontext *)sigctx;
750
751         ctx->SC_EAX = mctx->eax;
752         ctx->SC_EBX = mctx->ebx;
753         ctx->SC_ECX = mctx->ecx;
754         ctx->SC_EDX = mctx->edx;
755         ctx->SC_EBP = mctx->ebp;
756         ctx->SC_ESP = mctx->esp;
757         ctx->SC_ESI = mctx->esi;
758         ctx->SC_EDI = mctx->edi;
759         ctx->SC_EIP = mctx->eip;
760 #endif
761 }       
762
763 gpointer
764 mono_arch_ip_from_context (void *sigctx)
765 {
766 #ifdef MONO_ARCH_USE_SIGACTION
767         ucontext_t *ctx = (ucontext_t*)sigctx;
768         return (gpointer)UCONTEXT_REG_EIP (ctx);
769 #else
770         struct sigcontext *ctx = sigctx;
771         return (gpointer)ctx->SC_EIP;
772 #endif  
773 }
774
775 gboolean
776 mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
777 {
778         MonoContext mctx;
779
780         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
781
782         mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, test_only);
783
784         mono_arch_monoctx_to_sigctx (&mctx, sigctx);
785
786         return TRUE;
787 }