Improved the debugger's exception handling code.
[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 gboolean
365 debugger_handle_exception (MonoContext *ctx, MonoObject *obj)
366 {
367         MonoDebuggerExceptionAction action;
368
369         if (!mono_debug_using_mono_debugger ())
370                 return FALSE;
371
372         if (!obj) {
373                 MonoException *ex = mono_get_exception_null_reference ();
374                 MONO_OBJECT_SETREF (ex, message, mono_string_new (mono_domain_get (), "Object reference not set to an instance of an object"));
375                 obj = (MonoObject *)ex;
376         } 
377
378         action = mono_debugger_throw_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
379
380         if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP) {
381                 /*
382                  * The debugger wants us to stop on the `throw' instruction.
383                  * By the time we get here, it already inserted a breakpoint there.
384                  */
385                 return TRUE;
386         } else if (action == MONO_DEBUGGER_EXCEPTION_ACTION_STOP_UNHANDLED) {
387                 MonoContext ctx_cp = *ctx;
388
389                 /*
390                  * The debugger wants us to stop only if this exception is user-unhandled.
391                  */
392
393                 if (!mono_handle_exception (&ctx_cp, obj, MONO_CONTEXT_GET_IP (ctx), TRUE)) {
394                         return mono_debugger_unhandled_exception (MONO_CONTEXT_GET_IP (ctx), MONO_CONTEXT_GET_SP (ctx), obj);
395                 }
396         }
397
398         return FALSE;
399 }
400
401 static void
402 throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
403                  unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
404                  unsigned long eip,  unsigned long esp, gboolean rethrow)
405 {
406         static void (*restore_context) (MonoContext *);
407         MonoContext ctx;
408
409         if (!restore_context)
410                 restore_context = mono_arch_get_restore_context ();
411
412         /* Pop argument and return address */
413         ctx.esp = esp + (2 * sizeof (gpointer));
414         ctx.eip = eip;
415         ctx.ebp = ebp;
416         ctx.edi = edi;
417         ctx.esi = esi;
418         ctx.ebx = ebx;
419         ctx.edx = edx;
420         ctx.ecx = ecx;
421         ctx.eax = eax;
422
423         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
424                 MonoException *mono_ex = (MonoException*)exc;
425                 if (!rethrow)
426                         mono_ex->stack_trace = NULL;
427         }
428
429         if (mono_debug_using_mono_debugger ()) {
430                 guint8 buf [16], *code;
431
432                 mono_breakpoint_clean_code (NULL, (gpointer)eip, 8, buf, sizeof (buf));
433                 code = buf + 8;
434
435                 if (buf [3] == 0xe8) {
436                         MonoContext ctx_cp = ctx;
437                         ctx_cp.eip = eip - 5;
438
439                         if (debugger_handle_exception (&ctx_cp, exc)) {
440                                 restore_context (&ctx_cp);
441                                 g_assert_not_reached ();
442                         }
443                 }
444         }
445
446         /* adjust eip so that it point into the call instruction */
447         ctx.eip -= 1;
448
449         mono_handle_exception (&ctx, exc, (gpointer)eip, FALSE);
450         restore_context (&ctx);
451
452         g_assert_not_reached ();
453 }
454
455 static guint8*
456 get_throw_exception (gboolean rethrow)
457 {
458         guint8 *start, *code;
459
460         start = code = mono_global_codeman_reserve (64);
461
462         x86_push_reg (code, X86_ESP);
463         x86_push_membase (code, X86_ESP, 4); /* IP */
464         x86_push_membase (code, X86_ESP, 12); /* exception */
465         x86_push_reg (code, X86_EBP);
466         x86_push_reg (code, X86_EDI);
467         x86_push_reg (code, X86_ESI);
468         x86_push_reg (code, X86_EBX);
469         x86_push_reg (code, X86_EDX);
470         x86_push_reg (code, X86_ECX);
471         x86_push_reg (code, X86_EAX);
472         x86_call_code (code, throw_exception);
473         /* we should never reach this breakpoint */
474         x86_breakpoint (code);
475
476         g_assert ((code - start) < 64);
477
478         return start;
479 }
480
481 /**
482  * mono_arch_get_throw_exception:
483  *
484  * Returns a function pointer which can be used to raise 
485  * exceptions. The returned function has the following 
486  * signature: void (*func) (MonoException *exc); 
487  * For example to raise an arithmetic exception you can use:
488  *
489  * x86_push_imm (code, mono_get_exception_arithmetic ()); 
490  * x86_call_code (code, arch_get_throw_exception ()); 
491  *
492  */
493 gpointer 
494 mono_arch_get_throw_exception (void)
495 {
496         static guint8 *start;
497         static int inited = 0;
498
499         if (inited)
500                 return start;
501
502         start = get_throw_exception (FALSE);
503
504         inited = 1;
505
506         return start;
507 }
508
509 gpointer 
510 mono_arch_get_rethrow_exception (void)
511 {
512         static guint8 *start;
513         static int inited = 0;
514
515         if (inited)
516                 return start;
517
518         start = get_throw_exception (TRUE);
519
520         inited = 1;
521
522         return start;
523 }
524
525 /**
526  * mono_arch_get_throw_exception_by_name:
527  *
528  * Returns a function pointer which can be used to raise 
529  * corlib exceptions. The returned function has the following 
530  * signature: void (*func) (gpointer ip, char *exc_name); 
531  * For example to raise an arithmetic exception you can use:
532  *
533  * x86_push_imm (code, "ArithmeticException"); 
534  * x86_push_imm (code, <IP>)
535  * x86_jump_code (code, arch_get_throw_exception_by_name ()); 
536  *
537  */
538 gpointer 
539 mono_arch_get_throw_exception_by_name (void)
540 {
541         static guint8* start;
542         static int inited = 0;
543         guint8 *code;
544
545         if (inited)
546                 return start;
547
548         inited = 1;
549         code = start = mono_global_codeman_reserve (32);
550
551         x86_push_membase (code, X86_ESP, 4); /* exception name */
552         x86_push_imm (code, "System");
553         x86_push_imm (code, mono_defaults.exception_class->image);
554         x86_call_code (code, mono_exception_from_name);
555         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
556         /* save the newly create object (overwrite exception name)*/
557         x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
558         x86_jump_code (code, mono_arch_get_throw_exception ());
559
560         g_assert ((code - start) < 32);
561
562         return start;
563 }
564
565 /**
566  * mono_arch_get_throw_corlib_exception:
567  *
568  * Returns a function pointer which can be used to raise 
569  * corlib exceptions. The returned function has the following 
570  * signature: void (*func) (guint32 ex_token, guint32 offset); 
571  * Here, offset is the offset which needs to be substracted from the caller IP 
572  * to get the IP of the throw. Passing the offset has the advantage that it 
573  * needs no relocations in the caller.
574  */
575 gpointer 
576 mono_arch_get_throw_corlib_exception (void)
577 {
578         static guint8* start;
579         static int inited = 0;
580         guint8 *code;
581
582         if (inited)
583                 return start;
584
585         inited = 1;
586         code = start = mono_global_codeman_reserve (64);
587
588         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4); /* token */
589         x86_alu_reg_imm (code, X86_ADD, X86_EAX, MONO_TOKEN_TYPE_DEF);
590         x86_push_reg (code, X86_EAX);
591         x86_push_imm (code, mono_defaults.exception_class->image);
592         x86_call_code (code, mono_exception_from_token);
593         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
594         /* Compute caller ip */
595         x86_pop_reg (code, X86_ECX);
596         /* Pop token */
597         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
598         x86_pop_reg (code, X86_EDX);
599         x86_alu_reg_reg (code, X86_SUB, X86_ECX, X86_EDX);
600         /* Push exception object */
601         x86_push_reg (code, X86_EAX);
602         /* Push throw IP */
603         x86_push_reg (code, X86_ECX);
604         x86_jump_code (code, mono_arch_get_throw_exception ());
605
606         g_assert ((code - start) < 64);
607
608         return start;
609 }
610
611 /* mono_arch_find_jit_info:
612  *
613  * This function is used to gather information from @ctx. It return the 
614  * MonoJitInfo of the corresponding function, unwinds one stack frame and
615  * stores the resulting context into @new_ctx. It also stores a string 
616  * describing the stack location into @trace (if not NULL), and modifies
617  * the @lmf if necessary. @native_offset return the IP offset from the 
618  * start of the function or -1 if that info is not available.
619  */
620 MonoJitInfo *
621 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
622                          MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
623 {
624         MonoJitInfo *ji;
625         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
626
627         /* Avoid costly table lookup during stack overflow */
628         if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
629                 ji = prev_ji;
630         else
631                 ji = mono_jit_info_table_find (domain, ip);
632
633         if (managed)
634                 *managed = FALSE;
635
636         *new_ctx = *ctx;
637
638         if (ji != NULL) {
639                 gssize regs [MONO_MAX_IREGS + 1];
640                 guint8 *cfa;
641                 guint32 unwind_info_len;
642                 guint8 *unwind_info;
643
644                 if (managed)
645                         if (!ji->method->wrapper_type)
646                                 *managed = TRUE;
647
648                 if (ji->from_aot)
649                         unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len);
650                 else
651                         unwind_info = mono_get_cached_unwind_info (ji->used_regs, &unwind_info_len);
652
653                 regs [X86_EAX] = new_ctx->eax;
654                 regs [X86_EBX] = new_ctx->ebx;
655                 regs [X86_ECX] = new_ctx->ecx;
656                 regs [X86_EDX] = new_ctx->edx;
657                 regs [X86_ESP] = new_ctx->esp;
658                 regs [X86_EBP] = new_ctx->ebp;
659                 regs [X86_ESI] = new_ctx->esi;
660                 regs [X86_EDI] = new_ctx->edi;
661                 regs [X86_NREG] = new_ctx->eip;
662
663                 mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
664                                                    (guint8*)ji->code_start + ji->code_size,
665                                                    ip, regs, MONO_MAX_IREGS + 1, &cfa);
666
667                 new_ctx->eax = regs [X86_EAX];
668                 new_ctx->ebx = regs [X86_EBX];
669                 new_ctx->ecx = regs [X86_ECX];
670                 new_ctx->edx = regs [X86_EDX];
671                 new_ctx->esp = regs [X86_ESP];
672                 new_ctx->ebp = regs [X86_EBP];
673                 new_ctx->esi = regs [X86_ESI];
674                 new_ctx->edi = regs [X86_EDI];
675                 new_ctx->eip = regs [X86_NREG];
676
677                 /* The CFA becomes the new SP value */
678                 new_ctx->esp = (gssize)cfa;
679
680                 /* Adjust IP */
681                 new_ctx->eip --;
682
683                 if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
684                         /* remove any unused lmf */
685                         *lmf = (gpointer)(((guint32)(*lmf)->previous_lmf) & ~1);
686                 }
687
688                 /* Pop arguments off the stack */
689                 {
690                         MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (ji->method)->param_count + 1);
691
692                         guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (ji->method), mono_method_signature (ji->method)->param_count, arg_info);
693                         new_ctx->esp += stack_to_pop;
694                 }
695
696                 return ji;
697         } else if (*lmf) {
698                 
699                 *new_ctx = *ctx;
700
701                 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
702                 } else {
703                         if (!((guint32)((*lmf)->previous_lmf) & 1))
704                                 /* Top LMF entry */
705                                 return (gpointer)-1;
706                         /* Trampoline lmf frame */
707                         memset (res, 0, sizeof (MonoJitInfo));
708                         res->method = (*lmf)->method;
709                 }
710
711                 new_ctx->esi = (*lmf)->esi;
712                 new_ctx->edi = (*lmf)->edi;
713                 new_ctx->ebx = (*lmf)->ebx;
714                 new_ctx->ebp = (*lmf)->ebp;
715                 new_ctx->eip = (*lmf)->eip;
716
717                 /* Check if we are in a trampoline LMF frame */
718                 if ((guint32)((*lmf)->previous_lmf) & 1) {
719                         /* lmf->esp is set by the trampoline code */
720                         new_ctx->esp = (*lmf)->esp;
721
722                         /* Pop arguments off the stack */
723                         /* FIXME: Handle the delegate case too ((*lmf)->method == NULL) */
724                         /* FIXME: Handle the IMT/vtable case too */
725                         if ((*lmf)->method && (*lmf)->method != MONO_FAKE_IMT_METHOD && (*lmf)->method != MONO_FAKE_VTABLE_METHOD) {
726                                 MonoMethod *method = (*lmf)->method;
727                                 MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (method)->param_count + 1);
728
729                                 guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (method), mono_method_signature (method)->param_count, arg_info);
730                                 new_ctx->esp += stack_to_pop;
731                         }
732                 }
733                 else
734                         /* the lmf is always stored on the stack, so the following
735                          * expression points to a stack location which can be used as ESP */
736                         new_ctx->esp = (unsigned long)&((*lmf)->eip);
737
738                 *lmf = (gpointer)(((guint32)(*lmf)->previous_lmf) & ~1);
739
740                 return ji ? ji : res;
741         }
742
743         return NULL;
744 }
745
746 #ifdef __sun
747 #define REG_EAX EAX
748 #define REG_EBX EBX
749 #define REG_ECX ECX
750 #define REG_EDX EDX
751 #define REG_EBP EBP
752 #define REG_ESP ESP
753 #define REG_ESI ESI
754 #define REG_EDI EDI
755 #define REG_EIP EIP
756 #endif
757
758 void
759 mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
760 {
761 #ifdef MONO_ARCH_USE_SIGACTION
762         ucontext_t *ctx = (ucontext_t*)sigctx;
763         
764         mctx->eax = UCONTEXT_REG_EAX (ctx);
765         mctx->ebx = UCONTEXT_REG_EBX (ctx);
766         mctx->ecx = UCONTEXT_REG_ECX (ctx);
767         mctx->edx = UCONTEXT_REG_EDX (ctx);
768         mctx->ebp = UCONTEXT_REG_EBP (ctx);
769         mctx->esp = UCONTEXT_REG_ESP (ctx);
770         mctx->esi = UCONTEXT_REG_ESI (ctx);
771         mctx->edi = UCONTEXT_REG_EDI (ctx);
772         mctx->eip = UCONTEXT_REG_EIP (ctx);
773 #else   
774         struct sigcontext *ctx = (struct sigcontext *)sigctx;
775
776         mctx->eax = ctx->SC_EAX;
777         mctx->ebx = ctx->SC_EBX;
778         mctx->ecx = ctx->SC_ECX;
779         mctx->edx = ctx->SC_EDX;
780         mctx->ebp = ctx->SC_EBP;
781         mctx->esp = ctx->SC_ESP;
782         mctx->esi = ctx->SC_ESI;
783         mctx->edi = ctx->SC_EDI;
784         mctx->eip = ctx->SC_EIP;
785 #endif
786 }
787
788 void
789 mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
790 {
791 #ifdef MONO_ARCH_USE_SIGACTION
792         ucontext_t *ctx = (ucontext_t*)sigctx;
793
794         UCONTEXT_REG_EAX (ctx) = mctx->eax;
795         UCONTEXT_REG_EBX (ctx) = mctx->ebx;
796         UCONTEXT_REG_ECX (ctx) = mctx->ecx;
797         UCONTEXT_REG_EDX (ctx) = mctx->edx;
798         UCONTEXT_REG_EBP (ctx) = mctx->ebp;
799         UCONTEXT_REG_ESP (ctx) = mctx->esp;
800         UCONTEXT_REG_ESI (ctx) = mctx->esi;
801         UCONTEXT_REG_EDI (ctx) = mctx->edi;
802         UCONTEXT_REG_EIP (ctx) = mctx->eip;
803 #else
804         struct sigcontext *ctx = (struct sigcontext *)sigctx;
805
806         ctx->SC_EAX = mctx->eax;
807         ctx->SC_EBX = mctx->ebx;
808         ctx->SC_ECX = mctx->ecx;
809         ctx->SC_EDX = mctx->edx;
810         ctx->SC_EBP = mctx->ebp;
811         ctx->SC_ESP = mctx->esp;
812         ctx->SC_ESI = mctx->esi;
813         ctx->SC_EDI = mctx->edi;
814         ctx->SC_EIP = mctx->eip;
815 #endif
816 }       
817
818 gpointer
819 mono_arch_ip_from_context (void *sigctx)
820 {
821 #ifdef MONO_ARCH_USE_SIGACTION
822         ucontext_t *ctx = (ucontext_t*)sigctx;
823         return (gpointer)UCONTEXT_REG_EIP (ctx);
824 #else
825         struct sigcontext *ctx = sigctx;
826         return (gpointer)ctx->SC_EIP;
827 #endif  
828 }
829
830 gboolean
831 mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
832 {
833         MonoContext mctx;
834
835         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
836
837         if (debugger_handle_exception (&mctx, (MonoObject *)obj))
838                 return TRUE;
839
840         mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, test_only);
841
842         mono_arch_monoctx_to_sigctx (&mctx, sigctx);
843
844         return TRUE;
845 }
846
847 static void
848 restore_soft_guard_pages (void)
849 {
850         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
851         if (jit_tls->stack_ovf_guard_base)
852                 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_NONE);
853 }
854
855 /* 
856  * this function modifies mctx so that when it is restored, it
857  * won't execcute starting at mctx.eip, but in a function that
858  * will restore the protection on the soft-guard pages and return back to
859  * continue at mctx.eip.
860  */
861 static void
862 prepare_for_guard_pages (MonoContext *mctx)
863 {
864         gpointer *sp;
865         sp = (gpointer)(mctx->esp);
866         sp -= 1;
867         /* the resturn addr */
868         sp [0] = (gpointer)(mctx->eip);
869         mctx->eip = (unsigned long)restore_soft_guard_pages;
870         mctx->esp = (unsigned long)sp;
871 }
872
873 static void
874 altstack_handle_and_restore (void *sigctx, gpointer obj, gboolean stack_ovf)
875 {
876         void (*restore_context) (MonoContext *);
877         MonoContext mctx;
878
879         restore_context = mono_arch_get_restore_context ();
880         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
881
882         if (debugger_handle_exception (&mctx, (MonoObject *)obj)) {
883                 if (stack_ovf)
884                         prepare_for_guard_pages (&mctx);
885                 restore_context (&mctx);
886         }
887
888         mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, FALSE);
889         if (stack_ovf)
890                 prepare_for_guard_pages (&mctx);
891         restore_context (&mctx);
892 }
893
894 void
895 mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean stack_ovf)
896 {
897 #ifdef MONO_ARCH_USE_SIGACTION
898         MonoException *exc = NULL;
899         ucontext_t *ctx = (ucontext_t*)sigctx;
900         MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), (gpointer)UCONTEXT_REG_EIP (ctx));
901         gpointer *sp;
902         int frame_size;
903
904         /* if we didn't find a managed method for the ip address and it matches the fault
905          * address, we assume we followed a broken pointer during an indirect call, so
906          * we try the lookup again with the return address pushed on the stack
907          */
908         if (!ji && fault_addr == (gpointer)UCONTEXT_REG_EIP (ctx)) {
909                 glong *sp = (gpointer)UCONTEXT_REG_ESP (ctx);
910                 ji = mono_jit_info_table_find (mono_domain_get (), (gpointer)sp [0]);
911                 if (ji)
912                         UCONTEXT_REG_EIP (ctx) = sp [0];
913         }
914         if (stack_ovf)
915                 exc = mono_domain_get ()->stack_overflow_ex;
916         if (!ji)
917                 mono_handle_native_sigsegv (SIGSEGV, sigctx);
918         /* setup a call frame on the real stack so that control is returned there
919          * and exception handling can continue.
920          * If this was a stack overflow the caller already ensured the stack pages
921          * needed have been unprotected.
922          * The frame looks like:
923          *   ucontext struct
924          *   test_only arg
925          *   exception arg
926          *   ctx arg
927          *   return ip
928          */
929         frame_size = sizeof (ucontext_t) + sizeof (gpointer) * 4;
930         frame_size += 15;
931         frame_size &= ~15;
932         sp = (gpointer)(UCONTEXT_REG_ESP (ctx) & ~15);
933         sp = (gpointer)((char*)sp - frame_size);
934         /* the incoming arguments are aligned to 16 bytes boundaries, so the return address IP
935          * goes at sp [-1]
936          */
937         sp [-1] = (gpointer)UCONTEXT_REG_EIP (ctx);
938         sp [0] = sp + 4;
939         sp [1] = exc;
940         sp [2] = (gpointer)stack_ovf;
941         /* may need to adjust pointers in the new struct copy, depending on the OS */
942         memcpy (sp + 4, ctx, sizeof (ucontext_t));
943         /* at the return form the signal handler execution starts in altstack_handle_and_restore() */
944         UCONTEXT_REG_EIP (ctx) = (unsigned long)altstack_handle_and_restore;
945         UCONTEXT_REG_ESP (ctx) = (unsigned long)(sp - 1);
946 #endif
947 }
948