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