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