Turn eval test into normal test case
[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_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
265 {
266         guint8 *start = NULL;
267         guint8 *code;
268
269         /* restore_contect (MonoContext *ctx) */
270
271         *ji = NULL;
272
273         start = code = mono_global_codeman_reserve (128);
274         
275         /* load ctx */
276         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
277
278         /* get return address, stored in ECX */
279         x86_mov_reg_membase (code, X86_ECX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, eip), 4);
280         /* restore EBX */
281         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebx), 4);
282         /* restore EDI */
283         x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, edi), 4);
284         /* restore ESI */
285         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esi), 4);
286         /* restore ESP */
287         x86_mov_reg_membase (code, X86_ESP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esp), 4);
288         /* save the return addr to the restored stack */
289         x86_push_reg (code, X86_ECX);
290         /* restore EBP */
291         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebp), 4);
292         /* restore ECX */
293         x86_mov_reg_membase (code, X86_ECX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ecx), 4);
294         /* restore EDX */
295         x86_mov_reg_membase (code, X86_EDX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, edx), 4);
296         /* restore EAX */
297         x86_mov_reg_membase (code, X86_EAX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, eax), 4);
298
299         /* jump to the saved IP */
300         x86_ret (code);
301
302         *code_size = code - start;
303
304         return start;
305 }
306
307 /*
308  * mono_arch_get_call_filter:
309  *
310  * Returns a pointer to a method which calls an exception filter. We
311  * also use this function to call finally handlers (we pass NULL as 
312  * @exc object in this case).
313  */
314 gpointer
315 mono_arch_get_call_filter_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
316 {
317         guint8* start;
318         guint8 *code;
319
320         *ji = NULL;
321
322         /* call_filter (MonoContext *ctx, unsigned long eip) */
323         start = code = mono_global_codeman_reserve (64);
324
325         x86_push_reg (code, X86_EBP);
326         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
327         x86_push_reg (code, X86_EBX);
328         x86_push_reg (code, X86_EDI);
329         x86_push_reg (code, X86_ESI);
330
331         /* load ctx */
332         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
333         /* load eip */
334         x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
335         /* save EBP */
336         x86_push_reg (code, X86_EBP);
337
338         /* set new EBP */
339         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebp), 4);
340         /* restore registers used by global register allocation (EBX & ESI) */
341         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebx), 4);
342         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esi), 4);
343         x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, edi), 4);
344
345         /* align stack and save ESP */
346         x86_mov_reg_reg (code, X86_EDX, X86_ESP, 4);
347         x86_alu_reg_imm (code, X86_AND, X86_ESP, -MONO_ARCH_FRAME_ALIGNMENT);
348         g_assert (MONO_ARCH_FRAME_ALIGNMENT >= 8);
349         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 8);
350         x86_push_reg (code, X86_EDX);
351
352         /* call the handler */
353         x86_call_reg (code, X86_ECX);
354
355         /* restore ESP */
356         x86_pop_reg (code, X86_ESP);
357
358         /* restore EBP */
359         x86_pop_reg (code, X86_EBP);
360
361         /* restore saved regs */
362         x86_pop_reg (code, X86_ESI);
363         x86_pop_reg (code, X86_EDI);
364         x86_pop_reg (code, X86_EBX);
365         x86_leave (code);
366         x86_ret (code);
367
368         *code_size = code - start;
369
370         g_assert ((code - start) < 64);
371         return start;
372 }
373
374 /*
375  * mono_x86_throw_exception:
376  *
377  *   C function called from the throw trampolines.
378  */
379 void
380 mono_x86_throw_exception (mgreg_t *regs, MonoObject *exc, 
381                                                   mgreg_t eip, gboolean rethrow)
382 {
383         static void (*restore_context) (MonoContext *);
384         MonoContext ctx;
385
386         if (!restore_context)
387                 restore_context = mono_get_restore_context ();
388
389         ctx.esp = regs [X86_ESP];
390         ctx.eip = eip;
391         ctx.ebp = regs [X86_EBP];
392         ctx.edi = regs [X86_EDI];
393         ctx.esi = regs [X86_ESI];
394         ctx.ebx = regs [X86_EBX];
395         ctx.edx = regs [X86_EDX];
396         ctx.ecx = regs [X86_ECX];
397         ctx.eax = regs [X86_EAX];
398
399 #ifdef __APPLE__
400         /* The OSX ABI specifies 16 byte alignment at call sites */
401         g_assert ((ctx.esp % MONO_ARCH_FRAME_ALIGNMENT) == 0);
402 #endif
403
404         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
405                 MonoException *mono_ex = (MonoException*)exc;
406                 if (!rethrow)
407                         mono_ex->stack_trace = NULL;
408         }
409
410         if (mono_debug_using_mono_debugger ()) {
411                 guint8 buf [16], *code;
412
413                 mono_breakpoint_clean_code (NULL, (gpointer)eip, 8, buf, sizeof (buf));
414                 code = buf + 8;
415
416                 if (buf [3] == 0xe8) {
417                         MonoContext ctx_cp = ctx;
418                         ctx_cp.eip = eip - 5;
419
420                         if (mono_debugger_handle_exception (&ctx_cp, exc)) {
421                                 restore_context (&ctx_cp);
422                                 g_assert_not_reached ();
423                         }
424                 }
425         }
426
427         /* adjust eip so that it point into the call instruction */
428         ctx.eip -= 1;
429
430         mono_handle_exception (&ctx, exc, (gpointer)eip, FALSE);
431
432         restore_context (&ctx);
433
434         g_assert_not_reached ();
435 }
436
437 void
438 mono_x86_throw_corlib_exception (mgreg_t *regs, guint32 ex_token_index, 
439                                                                  mgreg_t eip, gint32 pc_offset)
440 {
441         guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
442         MonoException *ex;
443
444         ex = mono_exception_from_token (mono_defaults.exception_class->image, ex_token);
445
446         eip -= pc_offset;
447
448         mono_x86_throw_exception (regs, (MonoObject*)ex, eip, FALSE);
449 }
450
451 /*
452  * get_throw_exception:
453  *
454  *  Generate a call to mono_x86_throw_exception/
455  * mono_x86_throw_corlib_exception.
456  * If LLVM is true, generate code which assumes the caller is LLVM generated code, 
457  * which doesn't push the arguments.
458  */
459 static guint8*
460 get_throw_exception (const char *name, gboolean rethrow, gboolean llvm, gboolean corlib, guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
461 {
462         guint8 *start, *code;
463         GSList *unwind_ops = NULL;
464         int i, stack_size, stack_offset, arg_offsets [5], regs_offset;
465
466         if (ji)
467                 *ji = NULL;
468
469         start = code = mono_global_codeman_reserve (128);
470
471         stack_size = 128;
472
473         /* 
474          * On apple, the stack is misaligned by the pushing of the return address.
475          */
476         if (!llvm && corlib)
477                 /* On OSX, we don't generate alignment code to save space */
478                 stack_size += 4;
479         else
480                 stack_size += MONO_ARCH_FRAME_ALIGNMENT - 4;
481
482         /*
483          * The stack looks like this:
484          * <pc offset> (only if corlib is TRUE)
485          * <exception object>/<type token>
486          * <return addr> <- esp (unaligned on apple)
487          */
488
489         mono_add_unwind_op_def_cfa (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4);
490         mono_add_unwind_op_offset (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4);
491
492         /* Alloc frame */
493         x86_alu_reg_imm (code, X86_SUB, X86_ESP, stack_size);
494         mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 4);
495
496         arg_offsets [0] = 0;
497         arg_offsets [1] = 4;
498         arg_offsets [2] = 8;
499         arg_offsets [3] = 12;
500         regs_offset = 16;
501
502         /* Save registers */
503         for (i = 0; i < X86_NREG; ++i)
504                 if (i != X86_ESP)
505                         x86_mov_membase_reg (code, X86_ESP, regs_offset + (i * 4), i, 4);
506         /* Calculate the offset between the current sp and the sp of the caller */
507         if (llvm) {
508                 /* LLVM doesn't push the arguments */
509                 stack_offset = stack_size + 4;
510         } else {
511                 if (corlib) {
512                         /* Two arguments */
513                         stack_offset = stack_size + 4 + 8;
514 #ifdef __APPLE__
515                         /* We don't generate stack alignment code on osx to save space */
516 #endif
517                 } else {
518                         /* One argument */
519                         stack_offset = stack_size + 4 + 4;
520 #ifdef __APPLE__
521                         /* Pop the alignment added by OP_THROW too */
522                         stack_offset += MONO_ARCH_FRAME_ALIGNMENT - 4;
523 #endif
524                 }
525         }
526         /* Save ESP */
527         x86_lea_membase (code, X86_EAX, X86_ESP, stack_offset);
528         x86_mov_membase_reg (code, X86_ESP, regs_offset + (X86_ESP * 4), X86_EAX, 4);
529
530         /* Set arg1 == regs */
531         x86_lea_membase (code, X86_EAX, X86_ESP, regs_offset);
532         x86_mov_membase_reg (code, X86_ESP, arg_offsets [0], X86_EAX, 4);
533         /* Set arg2 == exc */
534         x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 4, 4);
535         x86_mov_membase_reg (code, X86_ESP, arg_offsets [1], X86_EAX, 4);
536         /* Set arg3 == eip */
537         x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size, 4);
538         x86_mov_membase_reg (code, X86_ESP, arg_offsets [2], X86_EAX, 4);
539         if (corlib) {
540                 /* Set arg4 == offset */
541                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 8, 4);
542                 x86_mov_membase_reg (code, X86_ESP, arg_offsets [3], X86_EAX, 4);
543         } else {
544                 /* Set arg4 == rethrow */
545                 x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], rethrow, 4);
546         }
547         /* Make the call */
548         if (aot) {
549                 // This can be called from runtime code, which can't guarantee that
550                 // ebx contains the got address.
551                 // So emit the got address loading code too
552                 code = mono_arch_emit_load_got_addr (start, code, NULL, ji);
553                 code = mono_arch_emit_load_aotconst (start, code, ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, corlib ? "mono_x86_throw_corlib_exception" : "mono_x86_throw_exception");
554                 x86_call_reg (code, X86_EAX);
555         } else {
556                 x86_call_code (code, corlib ? (gpointer)mono_x86_throw_corlib_exception : (gpointer)mono_x86_throw_exception);
557         }
558         x86_breakpoint (code);
559
560         g_assert ((code - start) < 128);
561
562         if (code_size)
563                 *code_size = code - start;
564
565         mono_save_trampoline_xdebug_info (corlib ? "llvm_throw_corlib_exception_trampoline" : "llvm_throw_exception_trampoline", start, code - start, unwind_ops);
566
567         return start;
568 }
569
570 /**
571  * mono_arch_get_throw_exception:
572  *
573  * Returns a function pointer which can be used to raise 
574  * exceptions. The returned function has the following 
575  * signature: void (*func) (MonoException *exc); 
576  * For example to raise an arithmetic exception you can use:
577  *
578  * x86_push_imm (code, mono_get_exception_arithmetic ()); 
579  * x86_call_code (code, arch_get_throw_exception ()); 
580  *
581  */
582 gpointer 
583 mono_arch_get_throw_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
584 {
585         return get_throw_exception ("throw_exception_trampoline", FALSE, FALSE, FALSE, code_size, ji, aot);
586 }
587
588 gpointer 
589 mono_arch_get_rethrow_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
590 {
591         return get_throw_exception ("rethow_exception_trampoline", TRUE, FALSE, FALSE, code_size, ji, aot);
592 }
593
594 /**
595  * mono_arch_get_throw_corlib_exception:
596  *
597  * Returns a function pointer which can be used to raise 
598  * corlib exceptions. The returned function has the following 
599  * signature: void (*func) (guint32 ex_token, guint32 offset); 
600  * Here, offset is the offset which needs to be substracted from the caller IP 
601  * to get the IP of the throw. Passing the offset has the advantage that it 
602  * needs no relocations in the caller.
603  */
604 gpointer 
605 mono_arch_get_throw_corlib_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
606 {
607         return get_throw_exception ("throw_corlib_exception_trampoline", FALSE, FALSE, TRUE, code_size, ji, aot);
608 }
609
610 void
611 mono_arch_exceptions_init (void)
612 {
613         guint8 *tramp;
614
615         if (mono_aot_only)
616                 return;
617
618         /* LLVM needs different throw trampolines */
619         tramp = get_throw_exception ("llvm_throw_exception_trampoline", FALSE, TRUE, FALSE, NULL, NULL, FALSE);
620
621         mono_register_jit_icall (tramp, "mono_arch_llvm_throw_exception", NULL, TRUE);
622
623         tramp = get_throw_exception ("llvm_throw_corlib_exception_trampoline", FALSE, TRUE, TRUE, NULL, NULL, FALSE);
624
625         mono_register_jit_icall (tramp, "mono_arch_llvm_throw_corlib_exception", NULL, TRUE);
626 }
627
628 /*
629  * mono_arch_find_jit_info_ext:
630  *
631  * See exceptions-amd64.c for docs.
632  */
633 gboolean
634 mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, 
635                                                          MonoJitInfo *ji, MonoContext *ctx, 
636                                                          MonoContext *new_ctx, MonoLMF **lmf, 
637                                                          StackFrameInfo *frame)
638 {
639         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
640
641         memset (frame, 0, sizeof (StackFrameInfo));
642         frame->ji = ji;
643         frame->managed = FALSE;
644
645         *new_ctx = *ctx;
646
647         if (ji != NULL) {
648                 gssize regs [MONO_MAX_IREGS + 1];
649                 guint8 *cfa;
650                 guint32 unwind_info_len;
651                 guint8 *unwind_info;
652
653                 frame->type = FRAME_TYPE_MANAGED;
654
655                 if (!ji->method->wrapper_type || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
656                         frame->managed = TRUE;
657
658                 if (ji->from_aot)
659                         unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len);
660                 else
661                         unwind_info = mono_get_cached_unwind_info (ji->used_regs, &unwind_info_len);
662
663                 regs [X86_EAX] = new_ctx->eax;
664                 regs [X86_EBX] = new_ctx->ebx;
665                 regs [X86_ECX] = new_ctx->ecx;
666                 regs [X86_EDX] = new_ctx->edx;
667                 regs [X86_ESP] = new_ctx->esp;
668                 regs [X86_EBP] = new_ctx->ebp;
669                 regs [X86_ESI] = new_ctx->esi;
670                 regs [X86_EDI] = new_ctx->edi;
671                 regs [X86_NREG] = new_ctx->eip;
672
673                 mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
674                                                    (guint8*)ji->code_start + ji->code_size,
675                                                    ip, regs, MONO_MAX_IREGS + 1, &cfa);
676
677                 new_ctx->eax = regs [X86_EAX];
678                 new_ctx->ebx = regs [X86_EBX];
679                 new_ctx->ecx = regs [X86_ECX];
680                 new_ctx->edx = regs [X86_EDX];
681                 new_ctx->esp = regs [X86_ESP];
682                 new_ctx->ebp = regs [X86_EBP];
683                 new_ctx->esi = regs [X86_ESI];
684                 new_ctx->edi = regs [X86_EDI];
685                 new_ctx->eip = regs [X86_NREG];
686
687                 /* The CFA becomes the new SP value */
688                 new_ctx->esp = (gssize)cfa;
689
690                 /* Adjust IP */
691                 new_ctx->eip --;
692
693                 if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
694                         /* remove any unused lmf */
695                         *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
696                 }
697
698                 /* Pop arguments off the stack */
699                 /* 
700                  * FIXME: LLVM doesn't push these, we can't use ji->from_llvm as it describes
701                  * the caller.
702                  */
703 #ifndef ENABLE_LLVM
704                 {
705                         MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (ji->method)->param_count + 1);
706
707                         guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (ji->method), mono_method_signature (ji->method)->param_count, arg_info);
708                         new_ctx->esp += stack_to_pop;
709                 }
710 #endif
711
712                 return TRUE;
713         } else if (*lmf) {
714
715                 if (((guint64)(*lmf)->previous_lmf) & 2) {
716                         /* 
717                          * This LMF entry is created by the soft debug code to mark transitions to
718                          * managed code done during invokes.
719                          */
720                         MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
721
722                         g_assert (ext->debugger_invoke);
723
724                         memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
725
726                         *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
727
728                         frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
729
730                         return TRUE;
731                 }
732                 
733                 if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL))) {
734                 } else {
735                         if (!((guint32)((*lmf)->previous_lmf) & 1))
736                                 /* Top LMF entry */
737                                 return FALSE;
738                         /* Trampoline lmf frame */
739                         frame->method = (*lmf)->method;
740                 }
741
742                 new_ctx->esi = (*lmf)->esi;
743                 new_ctx->edi = (*lmf)->edi;
744                 new_ctx->ebx = (*lmf)->ebx;
745                 new_ctx->ebp = (*lmf)->ebp;
746                 new_ctx->eip = (*lmf)->eip;
747
748                 frame->ji = ji;
749                 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
750
751                 /* Check if we are in a trampoline LMF frame */
752                 if ((guint32)((*lmf)->previous_lmf) & 1) {
753                         /* lmf->esp is set by the trampoline code */
754                         new_ctx->esp = (*lmf)->esp;
755
756                         /* Pop arguments off the stack */
757                         /* FIXME: Handle the delegate case too ((*lmf)->method == NULL) */
758                         /* FIXME: Handle the IMT/vtable case too */
759 #ifndef ENABLE_LLVM
760                         if ((*lmf)->method && (*lmf)->method != MONO_FAKE_IMT_METHOD && (*lmf)->method != MONO_FAKE_VTABLE_METHOD) {
761                                 MonoMethod *method = (*lmf)->method;
762                                 MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (method)->param_count + 1);
763
764                                 guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (method), mono_method_signature (method)->param_count, arg_info);
765                                 new_ctx->esp += stack_to_pop;
766                         }
767 #endif
768                 }
769                 else
770                         /* the lmf is always stored on the stack, so the following
771                          * expression points to a stack location which can be used as ESP */
772                         new_ctx->esp = (unsigned long)&((*lmf)->eip);
773
774                 *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
775
776                 return TRUE;
777         }
778
779         return FALSE;
780 }
781
782 #ifdef __sun
783 #define REG_EAX EAX
784 #define REG_EBX EBX
785 #define REG_ECX ECX
786 #define REG_EDX EDX
787 #define REG_EBP EBP
788 #define REG_ESP ESP
789 #define REG_ESI ESI
790 #define REG_EDI EDI
791 #define REG_EIP EIP
792 #endif
793
794 void
795 mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
796 {
797 #ifdef MONO_ARCH_USE_SIGACTION
798         ucontext_t *ctx = (ucontext_t*)sigctx;
799         
800         mctx->eax = UCONTEXT_REG_EAX (ctx);
801         mctx->ebx = UCONTEXT_REG_EBX (ctx);
802         mctx->ecx = UCONTEXT_REG_ECX (ctx);
803         mctx->edx = UCONTEXT_REG_EDX (ctx);
804         mctx->ebp = UCONTEXT_REG_EBP (ctx);
805         mctx->esp = UCONTEXT_REG_ESP (ctx);
806         mctx->esi = UCONTEXT_REG_ESI (ctx);
807         mctx->edi = UCONTEXT_REG_EDI (ctx);
808         mctx->eip = UCONTEXT_REG_EIP (ctx);
809 #else   
810         struct sigcontext *ctx = (struct sigcontext *)sigctx;
811
812         mctx->eax = ctx->SC_EAX;
813         mctx->ebx = ctx->SC_EBX;
814         mctx->ecx = ctx->SC_ECX;
815         mctx->edx = ctx->SC_EDX;
816         mctx->ebp = ctx->SC_EBP;
817         mctx->esp = ctx->SC_ESP;
818         mctx->esi = ctx->SC_ESI;
819         mctx->edi = ctx->SC_EDI;
820         mctx->eip = ctx->SC_EIP;
821 #endif
822 }
823
824 void
825 mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
826 {
827 #ifdef MONO_ARCH_USE_SIGACTION
828         ucontext_t *ctx = (ucontext_t*)sigctx;
829
830         UCONTEXT_REG_EAX (ctx) = mctx->eax;
831         UCONTEXT_REG_EBX (ctx) = mctx->ebx;
832         UCONTEXT_REG_ECX (ctx) = mctx->ecx;
833         UCONTEXT_REG_EDX (ctx) = mctx->edx;
834         UCONTEXT_REG_EBP (ctx) = mctx->ebp;
835         UCONTEXT_REG_ESP (ctx) = mctx->esp;
836         UCONTEXT_REG_ESI (ctx) = mctx->esi;
837         UCONTEXT_REG_EDI (ctx) = mctx->edi;
838         UCONTEXT_REG_EIP (ctx) = mctx->eip;
839 #else
840         struct sigcontext *ctx = (struct sigcontext *)sigctx;
841
842         ctx->SC_EAX = mctx->eax;
843         ctx->SC_EBX = mctx->ebx;
844         ctx->SC_ECX = mctx->ecx;
845         ctx->SC_EDX = mctx->edx;
846         ctx->SC_EBP = mctx->ebp;
847         ctx->SC_ESP = mctx->esp;
848         ctx->SC_ESI = mctx->esi;
849         ctx->SC_EDI = mctx->edi;
850         ctx->SC_EIP = mctx->eip;
851 #endif
852 }       
853
854 gpointer
855 mono_arch_ip_from_context (void *sigctx)
856 {
857 #ifdef MONO_ARCH_USE_SIGACTION
858         ucontext_t *ctx = (ucontext_t*)sigctx;
859         return (gpointer)UCONTEXT_REG_EIP (ctx);
860 #else
861         struct sigcontext *ctx = sigctx;
862         return (gpointer)ctx->SC_EIP;
863 #endif  
864 }
865
866 gboolean
867 mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
868 {
869         MonoContext mctx;
870
871         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
872
873         if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj))
874                 return TRUE;
875
876         mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, test_only);
877
878         mono_arch_monoctx_to_sigctx (&mctx, sigctx);
879
880         return TRUE;
881 }
882
883 static void
884 restore_soft_guard_pages (void)
885 {
886         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
887         if (jit_tls->stack_ovf_guard_base)
888                 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_NONE);
889 }
890
891 /* 
892  * this function modifies mctx so that when it is restored, it
893  * won't execcute starting at mctx.eip, but in a function that
894  * will restore the protection on the soft-guard pages and return back to
895  * continue at mctx.eip.
896  */
897 static void
898 prepare_for_guard_pages (MonoContext *mctx)
899 {
900         gpointer *sp;
901         sp = (gpointer)(mctx->esp);
902         sp -= 1;
903         /* the resturn addr */
904         sp [0] = (gpointer)(mctx->eip);
905         mctx->eip = (unsigned long)restore_soft_guard_pages;
906         mctx->esp = (unsigned long)sp;
907 }
908
909 static void
910 altstack_handle_and_restore (void *sigctx, gpointer obj, gboolean stack_ovf)
911 {
912         void (*restore_context) (MonoContext *);
913         MonoContext mctx;
914
915         restore_context = mono_get_restore_context ();
916         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
917
918         if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj)) {
919                 if (stack_ovf)
920                         prepare_for_guard_pages (&mctx);
921                 restore_context (&mctx);
922         }
923
924         mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, FALSE);
925         if (stack_ovf)
926                 prepare_for_guard_pages (&mctx);
927         restore_context (&mctx);
928 }
929
930 void
931 mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean stack_ovf)
932 {
933 #ifdef MONO_ARCH_USE_SIGACTION
934         MonoException *exc = NULL;
935         ucontext_t *ctx = (ucontext_t*)sigctx;
936         MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)UCONTEXT_REG_EIP (ctx), NULL);
937         gpointer *sp;
938         int frame_size;
939
940         /* if we didn't find a managed method for the ip address and it matches the fault
941          * address, we assume we followed a broken pointer during an indirect call, so
942          * we try the lookup again with the return address pushed on the stack
943          */
944         if (!ji && fault_addr == (gpointer)UCONTEXT_REG_EIP (ctx)) {
945                 glong *sp = (gpointer)UCONTEXT_REG_ESP (ctx);
946                 ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)sp [0], NULL);
947                 if (ji)
948                         UCONTEXT_REG_EIP (ctx) = sp [0];
949         }
950         if (stack_ovf)
951                 exc = mono_domain_get ()->stack_overflow_ex;
952         if (!ji)
953                 mono_handle_native_sigsegv (SIGSEGV, sigctx);
954         /* setup a call frame on the real stack so that control is returned there
955          * and exception handling can continue.
956          * If this was a stack overflow the caller already ensured the stack pages
957          * needed have been unprotected.
958          * The frame looks like:
959          *   ucontext struct
960          *   test_only arg
961          *   exception arg
962          *   ctx arg
963          *   return ip
964          */
965         frame_size = sizeof (ucontext_t) + sizeof (gpointer) * 4;
966         frame_size += 15;
967         frame_size &= ~15;
968         sp = (gpointer)(UCONTEXT_REG_ESP (ctx) & ~15);
969         sp = (gpointer)((char*)sp - frame_size);
970         /* the incoming arguments are aligned to 16 bytes boundaries, so the return address IP
971          * goes at sp [-1]
972          */
973         sp [-1] = (gpointer)UCONTEXT_REG_EIP (ctx);
974         sp [0] = sp + 4;
975         sp [1] = exc;
976         sp [2] = (gpointer)stack_ovf;
977         /* may need to adjust pointers in the new struct copy, depending on the OS */
978         memcpy (sp + 4, ctx, sizeof (ucontext_t));
979         /* at the return form the signal handler execution starts in altstack_handle_and_restore() */
980         UCONTEXT_REG_EIP (ctx) = (unsigned long)altstack_handle_and_restore;
981         UCONTEXT_REG_ESP (ctx) = (unsigned long)(sp - 1);
982 #endif
983 }
984
985 #if MONO_SUPPORT_TASKLETS
986 MonoContinuationRestore
987 mono_tasklets_arch_restore (void)
988 {
989         static guint8* saved = NULL;
990         guint8 *code, *start;
991
992         if (saved)
993                 return (MonoContinuationRestore)saved;
994         code = start = mono_global_codeman_reserve (48);
995         /* the signature is: restore (MonoContinuation *cont, int state, MonoLMF **lmf_addr) */
996         /* put cont in edx */
997         x86_mov_reg_membase (code, X86_EDX, X86_ESP, 4, 4);
998         /* setup the copy of the stack */
999         x86_mov_reg_membase (code, X86_ECX, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, stack_used_size), 4);
1000         x86_shift_reg_imm (code, X86_SHR, X86_ECX, 2);
1001         x86_cld (code);
1002         x86_mov_reg_membase (code, X86_ESI, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, saved_stack), 4);
1003         x86_mov_reg_membase (code, X86_EDI, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, return_sp), 4);
1004         x86_prefix (code, X86_REP_PREFIX);
1005         x86_movsl (code);
1006
1007         /* now restore the registers from the LMF */
1008         x86_mov_reg_membase (code, X86_ECX, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, lmf), 4);
1009         x86_mov_reg_membase (code, X86_EBX, X86_ECX, G_STRUCT_OFFSET (MonoLMF, ebx), 4);
1010         x86_mov_reg_membase (code, X86_EBP, X86_ECX, G_STRUCT_OFFSET (MonoLMF, ebp), 4);
1011         x86_mov_reg_membase (code, X86_ESI, X86_ECX, G_STRUCT_OFFSET (MonoLMF, esi), 4);
1012         x86_mov_reg_membase (code, X86_EDI, X86_ECX, G_STRUCT_OFFSET (MonoLMF, edi), 4);
1013
1014         /* restore the lmf chain */
1015         /*x86_mov_reg_membase (code, X86_ECX, X86_ESP, 12, 4);
1016         x86_mov_membase_reg (code, X86_ECX, 0, X86_EDX, 4);*/
1017
1018         /* state in eax, so it's setup as the return value */
1019         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 8, 4);
1020         x86_jump_membase (code, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, return_ip));
1021         g_assert ((code - start) <= 48);
1022         saved = start;
1023         return (MonoContinuationRestore)saved;
1024 }
1025 #endif
1026