2009-10-24 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / exceptions-amd64.c
1 /*
2  * exceptions-amd64.c: exception support for AMD64
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 #ifdef HAVE_UCONTEXT_H
15 #include <ucontext.h>
16 #endif
17
18 #include <mono/arch/amd64/amd64-codegen.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/threads.h>
22 #include <mono/metadata/threads-types.h>
23 #include <mono/metadata/debug-helpers.h>
24 #include <mono/metadata/exception.h>
25 #include <mono/metadata/gc-internal.h>
26 #include <mono/metadata/mono-debug.h>
27 #include <mono/utils/mono-mmap.h>
28
29 #include "mini.h"
30 #include "mini-amd64.h"
31 #include "tasklets.h"
32 #include "debug-mini.h"
33
34 #define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
35
36 #ifdef PLATFORM_WIN32
37 static MonoW32ExceptionHandler fpe_handler;
38 static MonoW32ExceptionHandler ill_handler;
39 static MonoW32ExceptionHandler segv_handler;
40
41 static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
42
43 #define W32_SEH_HANDLE_EX(_ex) \
44         if (_ex##_handler) _ex##_handler((int)sctx)
45
46 /*
47  * Unhandled Exception Filter
48  * Top-level per-process exception handler.
49  */
50 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep)
51 {
52         EXCEPTION_RECORD* er;
53         CONTEXT* ctx;
54         MonoContext* sctx;
55         LONG res;
56
57         res = EXCEPTION_CONTINUE_EXECUTION;
58
59         er = ep->ExceptionRecord;
60         ctx = ep->ContextRecord;
61         sctx = g_malloc(sizeof(MonoContext));
62
63         /* Copy Win32 context to UNIX style context */
64         sctx->rax = ctx->Rax;
65         sctx->rbx = ctx->Rbx;
66         sctx->rcx = ctx->Rcx;
67         sctx->rdx = ctx->Rdx;
68         sctx->rbp = ctx->Rbp;
69         sctx->rsp = ctx->Rsp;
70         sctx->rsi = ctx->Rsi;
71         sctx->rdi = ctx->Rdi;
72         sctx->rip = ctx->Rip;
73         sctx->r12 = ctx->R12;
74         sctx->r13 = ctx->R13;
75         sctx->r14 = ctx->R14;
76         sctx->r15 = ctx->R15;
77
78         switch (er->ExceptionCode) {
79         case EXCEPTION_ACCESS_VIOLATION:
80                 W32_SEH_HANDLE_EX(segv);
81                 break;
82         case EXCEPTION_ILLEGAL_INSTRUCTION:
83                 W32_SEH_HANDLE_EX(ill);
84                 break;
85         case EXCEPTION_INT_DIVIDE_BY_ZERO:
86         case EXCEPTION_INT_OVERFLOW:
87         case EXCEPTION_FLT_DIVIDE_BY_ZERO:
88         case EXCEPTION_FLT_OVERFLOW:
89         case EXCEPTION_FLT_UNDERFLOW:
90         case EXCEPTION_FLT_INEXACT_RESULT:
91                 W32_SEH_HANDLE_EX(fpe);
92                 break;
93         default:
94                 break;
95         }
96
97         /* Copy context back */
98         /* Nonvolatile */
99         ctx->Rsp = sctx->rsp; 
100         ctx->Rdi = sctx->rdi; 
101         ctx->Rsi = sctx->rsi; 
102         ctx->Rbx = sctx->rbx; 
103         ctx->Rbp = sctx->rbp;
104         ctx->R12 = sctx->r12; 
105         ctx->R13 = sctx->r13; 
106         ctx->R14 = sctx->r14;
107         ctx->R15 = sctx->r15;
108         ctx->Rip = sctx->rip; 
109
110         /* Volatile But should not matter?*/
111         ctx->Rax = sctx->rax; 
112         ctx->Rcx = sctx->rcx; 
113         ctx->Rdx = sctx->rdx;
114
115         g_free (sctx);
116
117         return res;
118 }
119
120 void win32_seh_init()
121 {
122         old_handler = SetUnhandledExceptionFilter(seh_handler);
123 }
124
125 void win32_seh_cleanup()
126 {
127         if (old_handler) SetUnhandledExceptionFilter(old_handler);
128 }
129
130 void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
131 {
132         switch (type) {
133         case SIGFPE:
134                 fpe_handler = handler;
135                 break;
136         case SIGILL:
137                 ill_handler = handler;
138                 break;
139         case SIGSEGV:
140                 segv_handler = handler;
141                 break;
142         default:
143                 break;
144         }
145 }
146
147 #endif /* PLATFORM_WIN32 */
148
149 /*
150  * mono_arch_get_restore_context:
151  *
152  * Returns a pointer to a method which restores a previously saved sigcontext.
153  */
154 gpointer
155 mono_arch_get_restore_context_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
156 {
157         guint8 *start = NULL;
158         guint8 *code;
159
160         /* restore_contect (MonoContext *ctx) */
161
162         *ji = NULL;
163
164         start = code = mono_global_codeman_reserve (256);
165
166         amd64_mov_reg_reg (code, AMD64_R11, AMD64_ARG_REG1, 8);
167
168         /* Restore all registers except %rip and %r11 */
169         amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rax), 8);
170         amd64_mov_reg_membase (code, AMD64_RCX, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rcx), 8);
171         amd64_mov_reg_membase (code, AMD64_RDX, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rdx), 8);
172         amd64_mov_reg_membase (code, AMD64_RBX, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rbx), 8);
173         amd64_mov_reg_membase (code, AMD64_RBP, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rbp), 8);
174         amd64_mov_reg_membase (code, AMD64_RSI, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rsi), 8);
175         amd64_mov_reg_membase (code, AMD64_RDI, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rdi), 8);
176         //amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, r8), 8);
177         //amd64_mov_reg_membase (code, AMD64_R9, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, r9), 8);
178         //amd64_mov_reg_membase (code, AMD64_R10, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, r10), 8);
179         amd64_mov_reg_membase (code, AMD64_R12, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, r12), 8);
180         amd64_mov_reg_membase (code, AMD64_R13, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, r13), 8);
181         amd64_mov_reg_membase (code, AMD64_R14, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, r14), 8);
182         amd64_mov_reg_membase (code, AMD64_R15, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, r15), 8);
183
184         if (mono_running_on_valgrind ()) {
185                 /* Prevent 'Address 0x... is just below the stack ptr.' errors */
186                 amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rsp), 8);
187                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rip), 8);
188                 amd64_mov_reg_reg (code, AMD64_RSP, AMD64_R8, 8);
189         } else {
190                 amd64_mov_reg_membase (code, AMD64_RSP, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rsp), 8);
191                 /* get return address */
192                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rip), 8);
193         }
194
195         /* jump to the saved IP */
196         amd64_jump_reg (code, AMD64_R11);
197
198         mono_arch_flush_icache (start, code - start);
199
200         *code_size = code - start;
201
202         return start;
203 }
204
205 /*
206  * mono_arch_get_call_filter:
207  *
208  * Returns a pointer to a method which calls an exception filter. We
209  * also use this function to call finally handlers (we pass NULL as 
210  * @exc object in this case).
211  */
212 gpointer
213 mono_arch_get_call_filter_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
214 {
215         guint8 *start;
216         int i;
217         guint8 *code;
218         guint32 pos;
219
220         *ji = NULL;
221
222         start = code = mono_global_codeman_reserve (128);
223
224         /* call_filter (MonoContext *ctx, unsigned long eip) */
225         code = start;
226
227         /* Alloc new frame */
228         amd64_push_reg (code, AMD64_RBP);
229         amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, 8);
230
231         /* Save callee saved regs */
232         pos = 0;
233         for (i = 0; i < AMD64_NREG; ++i)
234                 if (AMD64_IS_CALLEE_SAVED_REG (i)) {
235                         amd64_push_reg (code, i);
236                         pos += 8;
237                 }
238
239         /* Save EBP */
240         pos += 8;
241         amd64_push_reg (code, AMD64_RBP);
242
243         /* Make stack misaligned, the call will make it aligned again */
244         if (! (pos & 8))
245                 amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
246
247         /* set new EBP */
248         amd64_mov_reg_membase (code, AMD64_RBP, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoContext, rbp), 8);
249         /* load callee saved regs */
250         amd64_mov_reg_membase (code, AMD64_RBX, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoContext, rbx), 8);
251         amd64_mov_reg_membase (code, AMD64_R12, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoContext, r12), 8);
252         amd64_mov_reg_membase (code, AMD64_R13, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoContext, r13), 8);
253         amd64_mov_reg_membase (code, AMD64_R14, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoContext, r14), 8);
254         amd64_mov_reg_membase (code, AMD64_R15, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoContext, r15), 8);
255 #ifdef PLATFORM_WIN32
256         amd64_mov_reg_membase (code, AMD64_RDI, AMD64_ARG_REG1,  G_STRUCT_OFFSET (MonoContext, rdi), 8);
257         amd64_mov_reg_membase (code, AMD64_RSI, AMD64_ARG_REG1,  G_STRUCT_OFFSET (MonoContext, rsi), 8);
258 #endif
259
260         /* call the handler */
261         amd64_call_reg (code, AMD64_ARG_REG2);
262
263         if (! (pos & 8))
264                 amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
265
266         /* restore RBP */
267         amd64_pop_reg (code, AMD64_RBP);
268
269         /* Restore callee saved regs */
270         for (i = AMD64_NREG; i >= 0; --i)
271                 if (AMD64_IS_CALLEE_SAVED_REG (i))
272                         amd64_pop_reg (code, i);
273
274         amd64_leave (code);
275         amd64_ret (code);
276
277         g_assert ((code - start) < 128);
278
279         mono_arch_flush_icache (start, code - start);
280
281         *code_size = code - start;
282
283         return start;
284 }
285
286 /* 
287  * The first few arguments are dummy, to force the other arguments to be passed on
288  * the stack, this avoids overwriting the argument registers in the throw trampoline.
289  */
290 void
291 mono_amd64_throw_exception (guint64 dummy1, guint64 dummy2, guint64 dummy3, guint64 dummy4,
292                                                         guint64 dummy5, guint64 dummy6,
293                                                         MonoObject *exc, guint64 rip, guint64 rsp,
294                                                         guint64 rbx, guint64 rbp, guint64 r12, guint64 r13, 
295                                                         guint64 r14, guint64 r15, guint64 rdi, guint64 rsi, 
296                                                         guint64 rax, guint64 rcx, guint64 rdx,
297                                                         guint64 rethrow)
298 {
299         static void (*restore_context) (MonoContext *);
300         MonoContext ctx;
301
302         if (!restore_context)
303                 restore_context = mono_get_restore_context ();
304
305         ctx.rsp = rsp;
306         ctx.rip = rip;
307         ctx.rbx = rbx;
308         ctx.rbp = rbp;
309         ctx.r12 = r12;
310         ctx.r13 = r13;
311         ctx.r14 = r14;
312         ctx.r15 = r15;
313         ctx.rdi = rdi;
314         ctx.rsi = rsi;
315         ctx.rax = rax;
316         ctx.rcx = rcx;
317         ctx.rdx = rdx;
318
319         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
320                 MonoException *mono_ex = (MonoException*)exc;
321                 if (!rethrow)
322                         mono_ex->stack_trace = NULL;
323         }
324
325         if (mono_debug_using_mono_debugger ()) {
326                 guint8 buf [16], *code;
327
328                 mono_breakpoint_clean_code (NULL, (gpointer)rip, 8, buf, sizeof (buf));
329                 code = buf + 8;
330
331                 if (buf [3] == 0xe8) {
332                         MonoContext ctx_cp = ctx;
333                         ctx_cp.rip = rip - 5;
334
335                         if (mono_debugger_handle_exception (&ctx_cp, exc)) {
336                                 restore_context (&ctx_cp);
337                                 g_assert_not_reached ();
338                         }
339                 }
340         }
341
342         /* adjust eip so that it point into the call instruction */
343         ctx.rip -= 1;
344
345         mono_handle_exception (&ctx, exc, (gpointer)rip, FALSE);
346         restore_context (&ctx);
347
348         g_assert_not_reached ();
349 }
350
351 static gpointer
352 get_throw_trampoline (gboolean rethrow, guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
353 {
354         guint8* start;
355         guint8 *code;
356
357         start = code = mono_global_codeman_reserve (64);
358
359         code = start;
360
361         *ji = NULL;
362
363         amd64_mov_reg_reg (code, AMD64_R11, AMD64_RSP, 8);
364
365         /* reverse order */
366         amd64_push_imm (code, rethrow);
367         amd64_push_reg (code, AMD64_RDX);
368         amd64_push_reg (code, AMD64_RCX);
369         amd64_push_reg (code, AMD64_RAX);
370         amd64_push_reg (code, AMD64_RSI);
371         amd64_push_reg (code, AMD64_RDI);
372         amd64_push_reg (code, AMD64_R15);
373         amd64_push_reg (code, AMD64_R14);
374         amd64_push_reg (code, AMD64_R13);
375         amd64_push_reg (code, AMD64_R12);
376         amd64_push_reg (code, AMD64_RBP);
377         amd64_push_reg (code, AMD64_RBX);
378
379         /* SP */
380         amd64_lea_membase (code, AMD64_RAX, AMD64_R11, 8);
381         amd64_push_reg (code, AMD64_RAX);
382
383         /* IP */
384         amd64_push_membase (code, AMD64_R11, 0);
385
386         /* Exception */
387         amd64_push_reg (code, AMD64_ARG_REG1);
388
389 #ifdef PLATFORM_WIN32
390         /* align stack */
391         amd64_push_imm (code, 0);
392         amd64_push_imm (code, 0);
393         amd64_push_imm (code, 0);
394         amd64_push_imm (code, 0);
395         amd64_push_imm (code, 0);
396         amd64_push_imm (code, 0);
397 #endif
398
399         if (aot) {
400                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_amd64_throw_exception");
401                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
402         } else {
403                 amd64_mov_reg_imm (code, AMD64_R11, mono_amd64_throw_exception);
404         }
405         amd64_call_reg (code, AMD64_R11);
406         amd64_breakpoint (code);
407
408         mono_arch_flush_icache (start, code - start);
409
410         g_assert ((code - start) < 64);
411
412         *code_size = code - start;
413
414         return start;
415 }
416
417 /**
418  * mono_arch_get_throw_exception:
419  *
420  * Returns a function pointer which can be used to raise 
421  * exceptions. The returned function has the following 
422  * signature: void (*func) (MonoException *exc); 
423  *
424  */
425 gpointer 
426 mono_arch_get_throw_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
427 {
428         return get_throw_trampoline (FALSE, code_size, ji, aot);
429 }
430
431 gpointer 
432 mono_arch_get_rethrow_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
433 {
434         return get_throw_trampoline (TRUE, code_size, ji, aot);
435 }
436
437 gpointer 
438 mono_arch_get_throw_exception_by_name_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
439 {       
440         guint8* start;
441         guint8 *code;
442
443         start = code = mono_global_codeman_reserve (64);
444
445         *ji = NULL;
446
447         /* Not used on amd64 */
448         amd64_breakpoint (code);
449
450         mono_arch_flush_icache (start, code - start);
451
452         *code_size = code - start;
453
454         return start;
455 }
456
457 /**
458  * mono_arch_get_throw_corlib_exception:
459  *
460  * Returns a function pointer which can be used to raise 
461  * corlib exceptions. The returned function has the following 
462  * signature: void (*func) (guint32 ex_token, guint32 offset); 
463  * Here, offset is the offset which needs to be substracted from the caller IP 
464  * to get the IP of the throw. Passing the offset has the advantage that it 
465  * needs no relocations in the caller.
466  */
467 gpointer 
468 mono_arch_get_throw_corlib_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
469 {
470         static guint8* start;
471         guint8 *code;
472         guint64 throw_ex;
473
474         start = code = mono_global_codeman_reserve (64);
475
476         *ji = NULL;
477
478         /* Push throw_ip */
479         amd64_push_reg (code, AMD64_ARG_REG2);
480
481         /* Call exception_from_token */
482         amd64_mov_reg_reg (code, AMD64_ARG_REG2, AMD64_ARG_REG1, 8);
483         if (aot) {
484                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_IMAGE, mono_defaults.exception_class->image);
485                 amd64_mov_reg_membase (code, AMD64_ARG_REG1, AMD64_RIP, 0, 8);
486                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_exception_from_token");
487                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
488         } else {
489                 amd64_mov_reg_imm (code, AMD64_ARG_REG1, mono_defaults.exception_class->image);
490                 amd64_mov_reg_imm (code, AMD64_R11, mono_exception_from_token);
491         }
492 #ifdef PLATFORM_WIN32
493         amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 32);
494 #endif
495         amd64_call_reg (code, AMD64_R11);
496 #ifdef PLATFORM_WIN32
497         amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 32);
498 #endif
499
500         /* Compute throw_ip */
501         amd64_pop_reg (code, AMD64_ARG_REG2);
502         /* return addr */
503         amd64_pop_reg (code, AMD64_ARG_REG3);
504         amd64_alu_reg_reg (code, X86_SUB, AMD64_ARG_REG3, AMD64_ARG_REG2);
505
506         /* Put the throw_ip at the top of the misaligned stack */
507         amd64_push_reg (code, AMD64_ARG_REG3);
508
509         throw_ex = (guint64)mono_get_throw_exception ();
510
511         /* Call throw_exception */
512         amd64_mov_reg_reg (code, AMD64_ARG_REG1, AMD64_RAX, 8);
513         if (aot) {
514                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_throw_exception");
515                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
516         } else {
517                 amd64_mov_reg_imm (code, AMD64_R11, throw_ex);
518         }
519         /* The original IP is on the stack */
520         amd64_jump_reg (code, AMD64_R11);
521
522         g_assert ((code - start) < 64);
523
524         mono_arch_flush_icache (start, code - start);
525
526         *code_size = code - start;
527
528         return start;
529 }
530
531 /* mono_arch_find_jit_info:
532  *
533  * This function is used to gather information from @ctx. It return the 
534  * MonoJitInfo of the corresponding function, unwinds one stack frame and
535  * stores the resulting context into @new_ctx. It also stores a string 
536  * describing the stack location into @trace (if not NULL), and modifies
537  * the @lmf if necessary. @native_offset return the IP offset from the 
538  * start of the function or -1 if that info is not available.
539  */
540 MonoJitInfo *
541 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
542                          MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
543 {
544         MonoJitInfo *ji;
545         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
546
547         /* Avoid costly table lookup during stack overflow */
548         if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
549                 ji = prev_ji;
550         else
551                 ji = mini_jit_info_table_find (domain, ip, NULL);
552
553         if (managed)
554                 *managed = FALSE;
555
556         *new_ctx = *ctx;
557
558         if (ji != NULL) {
559                 gssize regs [MONO_MAX_IREGS + 1];
560                 guint8 *cfa;
561                 guint32 unwind_info_len;
562                 guint8 *unwind_info;
563
564                 if (managed)
565                         if (!ji->method->wrapper_type)
566                                 *managed = TRUE;
567
568                 if (ji->from_aot)
569                         unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len);
570                 else
571                         unwind_info = mono_get_cached_unwind_info (ji->used_regs, &unwind_info_len);
572  
573                 regs [AMD64_RAX] = new_ctx->rax;
574                 regs [AMD64_RBX] = new_ctx->rbx;
575                 regs [AMD64_RCX] = new_ctx->rcx;
576                 regs [AMD64_RDX] = new_ctx->rdx;
577                 regs [AMD64_RBP] = new_ctx->rbp;
578                 regs [AMD64_RSP] = new_ctx->rsp;
579                 regs [AMD64_RSI] = new_ctx->rsi;
580                 regs [AMD64_RDI] = new_ctx->rdi;
581                 regs [AMD64_RIP] = new_ctx->rip;
582                 regs [AMD64_R12] = new_ctx->r12;
583                 regs [AMD64_R13] = new_ctx->r13;
584                 regs [AMD64_R14] = new_ctx->r14;
585                 regs [AMD64_R15] = new_ctx->r15;
586
587                 mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
588                                                    (guint8*)ji->code_start + ji->code_size,
589                                                    ip, regs, MONO_MAX_IREGS + 1, &cfa);
590
591                 new_ctx->rax = regs [AMD64_RAX];
592                 new_ctx->rbx = regs [AMD64_RBX];
593                 new_ctx->rcx = regs [AMD64_RCX];
594                 new_ctx->rdx = regs [AMD64_RDX];
595                 new_ctx->rbp = regs [AMD64_RBP];
596                 new_ctx->rsp = regs [AMD64_RSP];
597                 new_ctx->rsi = regs [AMD64_RSI];
598                 new_ctx->rdi = regs [AMD64_RDI];
599                 new_ctx->rip = regs [AMD64_RIP];
600                 new_ctx->r12 = regs [AMD64_R12];
601                 new_ctx->r13 = regs [AMD64_R13];
602                 new_ctx->r14 = regs [AMD64_R14];
603                 new_ctx->r15 = regs [AMD64_R15];
604  
605                 /* The CFA becomes the new SP value */
606                 new_ctx->rsp = (gssize)cfa;
607
608                 /* Adjust IP */
609                 new_ctx->rip --;
610
611                 if (*lmf && ((*lmf) != jit_tls->first_lmf) && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->rsp)) {
612                         /* remove any unused lmf */
613                         *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~1);
614                 }
615
616 #ifndef MONO_AMD64_NO_PUSHES
617                 /* Pop arguments off the stack */
618                 {
619                         MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (ji->method)->param_count + 1);
620
621                         guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (ji->method), mono_method_signature (ji->method)->param_count, arg_info);
622                         new_ctx->rsp += stack_to_pop;
623                 }
624 #endif
625
626                 return ji;
627         } else if (*lmf) {
628                 guint64 rip;
629
630                 if (((guint64)(*lmf)->previous_lmf) & 1) {
631                         /* This LMF has the rip field set */
632                         rip = (*lmf)->rip;
633                 } else if ((*lmf)->rsp == 0) {
634                         /* Top LMF entry */
635                         return (gpointer)-1;
636                 } else {
637                         /* 
638                          * The rsp field is set just before the call which transitioned to native 
639                          * code. Obtain the rip from the stack.
640                          */
641                         rip = *(guint64*)((*lmf)->rsp - sizeof (gpointer));
642                 }
643
644                 ji = mini_jit_info_table_find (domain, (gpointer)rip, NULL);
645                 if (!ji) {
646                         // FIXME: This can happen with multiple appdomains (bug #444383)
647                         return (gpointer)-1;
648                 }
649
650                 new_ctx->rip = rip;
651                 new_ctx->rbp = (*lmf)->rbp;
652                 new_ctx->rsp = (*lmf)->rsp;
653
654                 new_ctx->rbx = (*lmf)->rbx;
655                 new_ctx->r12 = (*lmf)->r12;
656                 new_ctx->r13 = (*lmf)->r13;
657                 new_ctx->r14 = (*lmf)->r14;
658                 new_ctx->r15 = (*lmf)->r15;
659 #ifdef PLATFORM_WIN32
660                 new_ctx->rdi = (*lmf)->rdi;
661                 new_ctx->rsi = (*lmf)->rsi;
662 #endif
663
664                 *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~1);
665
666                 return ji ? ji : res;
667         }
668
669         return NULL;
670 }
671
672 /**
673  * mono_arch_handle_exception:
674  *
675  * @ctx: saved processor state
676  * @obj: the exception object
677  */
678 gboolean
679 mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
680 {
681         MonoContext mctx;
682
683         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
684
685         if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj))
686                 return TRUE;
687
688         mono_handle_exception (&mctx, obj, MONO_CONTEXT_GET_IP (&mctx), test_only);
689
690         mono_arch_monoctx_to_sigctx (&mctx, sigctx);
691
692         return TRUE;
693 }
694
695 #ifdef MONO_ARCH_USE_SIGACTION
696 static inline guint64*
697 gregs_from_ucontext (ucontext_t *ctx)
698 {
699         return (guint64 *) UCONTEXT_GREGS (ctx);
700 }
701 #endif
702 void
703 mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
704 {
705 #ifdef MONO_ARCH_USE_SIGACTION
706         ucontext_t *ctx = (ucontext_t*)sigctx;
707
708     guint64 *gregs = gregs_from_ucontext (ctx);
709
710         mctx->rax = gregs [REG_RAX];
711         mctx->rbx = gregs [REG_RBX];
712         mctx->rcx = gregs [REG_RCX];
713         mctx->rdx = gregs [REG_RDX];
714         mctx->rbp = gregs [REG_RBP];
715         mctx->rsp = gregs [REG_RSP];
716         mctx->rsi = gregs [REG_RSI];
717         mctx->rdi = gregs [REG_RDI];
718         mctx->rip = gregs [REG_RIP];
719         mctx->r12 = gregs [REG_R12];
720         mctx->r13 = gregs [REG_R13];
721         mctx->r14 = gregs [REG_R14];
722         mctx->r15 = gregs [REG_R15];
723 #else
724         MonoContext *ctx = (MonoContext *)sigctx;
725
726         mctx->rax = ctx->rax;
727         mctx->rbx = ctx->rbx;
728         mctx->rcx = ctx->rcx;
729         mctx->rdx = ctx->rdx;
730         mctx->rbp = ctx->rbp;
731         mctx->rsp = ctx->rsp;
732         mctx->rsi = ctx->rsi;
733         mctx->rdi = ctx->rdi;
734         mctx->rip = ctx->rip;
735         mctx->r12 = ctx->r12;
736         mctx->r13 = ctx->r13;
737         mctx->r14 = ctx->r14;
738         mctx->r15 = ctx->r15;
739 #endif
740 }
741
742 void
743 mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
744 {
745 #ifdef MONO_ARCH_USE_SIGACTION
746         ucontext_t *ctx = (ucontext_t*)sigctx;
747
748     guint64 *gregs = gregs_from_ucontext (ctx);
749
750         gregs [REG_RAX] = mctx->rax;
751         gregs [REG_RBX] = mctx->rbx;
752         gregs [REG_RCX] = mctx->rcx;
753         gregs [REG_RDX] = mctx->rdx;
754         gregs [REG_RBP] = mctx->rbp;
755         gregs [REG_RSP] = mctx->rsp;
756         gregs [REG_RSI] = mctx->rsi;
757         gregs [REG_RDI] = mctx->rdi;
758         gregs [REG_RIP] = mctx->rip;
759         gregs [REG_R12] = mctx->r12;
760         gregs [REG_R13] = mctx->r13;
761         gregs [REG_R14] = mctx->r14;
762         gregs [REG_R15] = mctx->r15;
763 #else
764         MonoContext *ctx = (MonoContext *)sigctx;
765
766         ctx->rax = mctx->rax;
767         ctx->rbx = mctx->rbx;
768         ctx->rcx = mctx->rcx;
769         ctx->rdx = mctx->rdx;
770         ctx->rbp = mctx->rbp;
771         ctx->rsp = mctx->rsp;
772         ctx->rsi = mctx->rsi;
773         ctx->rdi = mctx->rdi;
774         ctx->rip = mctx->rip;
775         ctx->r12 = mctx->r12;
776         ctx->r13 = mctx->r13;
777         ctx->r14 = mctx->r14;
778         ctx->r15 = mctx->r15;
779 #endif
780 }
781
782 gpointer
783 mono_arch_ip_from_context (void *sigctx)
784 {
785         
786 #ifdef MONO_ARCH_USE_SIGACTION
787
788         ucontext_t *ctx = (ucontext_t*)sigctx;
789
790     guint64 *gregs = gregs_from_ucontext (ctx);
791
792         return (gpointer)gregs [REG_RIP];
793 #else
794         MonoContext *ctx = sigctx;
795         return (gpointer)ctx->rip;
796 #endif  
797 }
798
799 static void
800 restore_soft_guard_pages (void)
801 {
802         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
803         if (jit_tls->stack_ovf_guard_base)
804                 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_NONE);
805 }
806
807 /* 
808  * this function modifies mctx so that when it is restored, it
809  * won't execcute starting at mctx.eip, but in a function that
810  * will restore the protection on the soft-guard pages and return back to
811  * continue at mctx.eip.
812  */
813 static void
814 prepare_for_guard_pages (MonoContext *mctx)
815 {
816         gpointer *sp;
817         sp = (gpointer)(mctx->rsp);
818         sp -= 1;
819         /* the return addr */
820         sp [0] = (gpointer)(mctx->rip);
821         mctx->rip = (guint64)restore_soft_guard_pages;
822         mctx->rsp = (guint64)sp;
823 }
824
825 static void
826 altstack_handle_and_restore (void *sigctx, gpointer obj, gboolean stack_ovf)
827 {
828         void (*restore_context) (MonoContext *);
829         MonoContext mctx;
830
831         restore_context = mono_get_restore_context ();
832         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
833
834         if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj)) {
835                 if (stack_ovf)
836                         prepare_for_guard_pages (&mctx);
837                 restore_context (&mctx);
838         }
839
840         mono_handle_exception (&mctx, obj, MONO_CONTEXT_GET_IP (&mctx), FALSE);
841         if (stack_ovf)
842                 prepare_for_guard_pages (&mctx);
843         restore_context (&mctx);
844 }
845
846 void
847 mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean stack_ovf)
848 {
849 #ifdef MONO_ARCH_USE_SIGACTION
850         MonoException *exc = NULL;
851         ucontext_t *ctx = (ucontext_t*)sigctx;
852         guint64 *gregs = gregs_from_ucontext (ctx);
853         MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)gregs [REG_RIP], NULL);
854         gpointer *sp;
855         int frame_size;
856
857         if (stack_ovf)
858                 exc = mono_domain_get ()->stack_overflow_ex;
859         if (!ji)
860                 mono_handle_native_sigsegv (SIGSEGV, sigctx);
861
862         /* setup a call frame on the real stack so that control is returned there
863          * and exception handling can continue.
864          * The frame looks like:
865          *   ucontext struct
866          *   ...
867          *   return ip
868          * 128 is the size of the red zone
869          */
870         frame_size = sizeof (ucontext_t) + sizeof (gpointer) * 4 + 128;
871         frame_size += 15;
872         frame_size &= ~15;
873         sp = (gpointer)(gregs [REG_RSP] & ~15);
874         sp = (gpointer)((char*)sp - frame_size);
875         /* the arguments must be aligned */
876         sp [-1] = (gpointer)gregs [REG_RIP];
877         /* may need to adjust pointers in the new struct copy, depending on the OS */
878         memcpy (sp + 4, ctx, sizeof (ucontext_t));
879         /* at the return form the signal handler execution starts in altstack_handle_and_restore() */
880         gregs [REG_RIP] = (unsigned long)altstack_handle_and_restore;
881         gregs [REG_RSP] = (unsigned long)(sp - 1);
882         gregs [REG_RDI] = (unsigned long)(sp + 4);
883         gregs [REG_RSI] = (guint64)exc;
884         gregs [REG_RDX] = stack_ovf;
885 #endif
886 }
887
888 guint64
889 mono_amd64_get_original_ip (void)
890 {
891         MonoLMF *lmf = mono_get_lmf ();
892
893         g_assert (lmf);
894
895         /* Reset the change to previous_lmf */
896         lmf->previous_lmf = (gpointer)((guint64)lmf->previous_lmf & ~1);
897
898         return lmf->rip;
899 }
900
901 gpointer
902 mono_arch_get_throw_pending_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
903 {
904         guint8 *code, *start;
905         guint8 *br[1];
906         gpointer throw_trampoline;
907
908         *ji = NULL;
909
910         start = code = mono_global_codeman_reserve (128);
911
912         /* We are in the frame of a managed method after a call */
913         /* 
914          * We would like to throw the pending exception in such a way that it looks to
915          * be thrown from the managed method.
916          */
917
918         /* Save registers which might contain the return value of the call */
919         amd64_push_reg (code, AMD64_RAX);
920         amd64_push_reg (code, AMD64_RDX);
921
922         amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
923         amd64_movsd_membase_reg (code, AMD64_RSP, 0, AMD64_XMM0);
924
925         /* Align stack */
926         amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
927
928         /* Obtain the pending exception */
929         if (aot) {
930                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_thread_get_and_clear_pending_exception");
931                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
932         } else {
933                 amd64_mov_reg_imm (code, AMD64_R11, mono_thread_get_and_clear_pending_exception);
934         }
935         amd64_call_reg (code, AMD64_R11);
936
937         /* Check if it is NULL, and branch */
938         amd64_alu_reg_imm (code, X86_CMP, AMD64_RAX, 0);
939         br[0] = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
940
941         /* exc != NULL branch */
942
943         /* Save the exc on the stack */
944         amd64_push_reg (code, AMD64_RAX);
945         /* Align stack */
946         amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
947
948         /* Obtain the original ip and clear the flag in previous_lmf */
949         if (aot) {
950                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_amd64_get_original_ip");
951                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
952         } else {
953                 amd64_mov_reg_imm (code, AMD64_R11, mono_amd64_get_original_ip);
954         }
955         amd64_call_reg (code, AMD64_R11);       
956
957         /* Load exc */
958         amd64_mov_reg_membase (code, AMD64_R11, AMD64_RSP, 8, 8);
959
960         /* Pop saved stuff from the stack */
961         amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 6 * 8);
962
963         /* Setup arguments for the throw trampoline */
964         /* Exception */
965         amd64_mov_reg_reg (code, AMD64_ARG_REG1, AMD64_R11, 8);
966         /* The trampoline expects the caller ip to be pushed on the stack */
967         amd64_push_reg (code, AMD64_RAX);
968
969         /* Call the throw trampoline */
970         if (aot) {
971                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_amd64_throw_exception");
972                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
973         } else {
974                 throw_trampoline = mono_get_throw_exception ();
975                 amd64_mov_reg_imm (code, AMD64_R11, throw_trampoline);
976         }
977         /* We use a jump instead of a call so we can push the original ip on the stack */
978         amd64_jump_reg (code, AMD64_R11);
979
980         /* ex == NULL branch */
981         mono_amd64_patch (br [0], code);
982
983         /* Obtain the original ip and clear the flag in previous_lmf */
984         if (aot) {
985                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_amd64_get_original_ip");
986                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
987         } else {
988                 amd64_mov_reg_imm (code, AMD64_R11, mono_amd64_get_original_ip);
989         }
990         amd64_call_reg (code, AMD64_R11);       
991         amd64_mov_reg_reg (code, AMD64_R11, AMD64_RAX, 8);
992
993         /* Restore registers */
994         amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
995         amd64_movsd_reg_membase (code, AMD64_XMM0, AMD64_RSP, 0);
996         amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
997         amd64_pop_reg (code, AMD64_RDX);
998         amd64_pop_reg (code, AMD64_RAX);
999
1000         /* Return to original code */
1001         amd64_jump_reg (code, AMD64_R11);
1002
1003         g_assert ((code - start) < 128);
1004
1005         *code_size = code - start;
1006
1007         return start;
1008 }
1009
1010 static gpointer throw_pending_exception;
1011
1012 /*
1013  * Called when a thread receives an async exception while executing unmanaged code.
1014  * Instead of checking for this exception in the managed-to-native wrapper, we hijack 
1015  * the return address on the stack to point to a helper routine which throws the
1016  * exception.
1017  */
1018 void
1019 mono_arch_notify_pending_exc (void)
1020 {
1021         MonoLMF *lmf = mono_get_lmf ();
1022
1023         if (lmf->rsp == 0)
1024                 /* Initial LMF */
1025                 return;
1026
1027         if ((guint64)lmf->previous_lmf & 1)
1028                 /* Already hijacked or trampoline LMF entry */
1029                 return;
1030
1031         /* lmf->rsp is set just before making the call which transitions to unmanaged code */
1032         lmf->rip = *(guint64*)(lmf->rsp - 8);
1033         /* Signal that lmf->rip is set */
1034         lmf->previous_lmf = (gpointer)((guint64)lmf->previous_lmf | 1);
1035
1036         *(gpointer*)(lmf->rsp - 8) = throw_pending_exception;
1037 }
1038
1039 void
1040 mono_arch_exceptions_init (void)
1041 {
1042         guint32 code_size;
1043         MonoJumpInfo *ji;
1044
1045         if (mono_aot_only) {
1046                 throw_pending_exception = mono_aot_get_named_code ("throw_pending_exception");
1047         } else {
1048                 /* Call this to avoid initialization races */
1049                 throw_pending_exception = mono_arch_get_throw_pending_exception_full (&code_size, &ji, FALSE);
1050         }
1051 }
1052
1053 #ifdef PLATFORM_WIN32
1054
1055 /*
1056  * The mono_arch_unwindinfo* methods are used to build and add
1057  * function table info for each emitted method from mono.  On Winx64
1058  * the seh handler will not be called if the mono methods are not
1059  * added to the function table.  
1060  *
1061  * We should not need to add non-volatile register info to the 
1062  * table since mono stores that info elsewhere. (Except for the register 
1063  * used for the fp.)
1064  */
1065
1066 #define MONO_MAX_UNWIND_CODES 22
1067
1068 typedef union _UNWIND_CODE {
1069     struct {
1070         guchar CodeOffset;
1071         guchar UnwindOp : 4;
1072         guchar OpInfo   : 4;
1073     };
1074     gushort FrameOffset;
1075 } UNWIND_CODE, *PUNWIND_CODE;
1076
1077 typedef struct _UNWIND_INFO {
1078         guchar Version       : 3;
1079         guchar Flags         : 5;
1080         guchar SizeOfProlog;
1081         guchar CountOfCodes;
1082         guchar FrameRegister : 4;
1083         guchar FrameOffset   : 4;
1084         /* custom size for mono allowing for mono allowing for*/
1085         /*UWOP_PUSH_NONVOL ebp offset = 21*/
1086         /*UWOP_ALLOC_LARGE : requires 2 or 3 offset = 20*/
1087         /*UWOP_SET_FPREG : requires 2 offset = 17*/
1088         /*UWOP_PUSH_NONVOL offset = 15-0*/
1089         UNWIND_CODE UnwindCode[MONO_MAX_UNWIND_CODES]; 
1090
1091 /*      UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
1092  *      union {
1093  *          OPTIONAL ULONG ExceptionHandler;
1094  *          OPTIONAL ULONG FunctionEntry;
1095  *      };
1096  *      OPTIONAL ULONG ExceptionData[]; */
1097 } UNWIND_INFO, *PUNWIND_INFO;
1098
1099 typedef struct
1100 {
1101         RUNTIME_FUNCTION runtimeFunction;
1102         UNWIND_INFO unwindInfo;
1103 } MonoUnwindInfo, *PMonoUnwindInfo;
1104
1105 static void
1106 mono_arch_unwindinfo_create (gpointer* monoui)
1107 {
1108         PMonoUnwindInfo newunwindinfo;
1109         *monoui = newunwindinfo = g_new0 (MonoUnwindInfo, 1);
1110         newunwindinfo->unwindInfo.Version = 1;
1111 }
1112
1113 void
1114 mono_arch_unwindinfo_add_push_nonvol (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg )
1115 {
1116         PMonoUnwindInfo unwindinfo;
1117         PUNWIND_CODE unwindcode;
1118         guchar codeindex;
1119         if (!*monoui)
1120                 mono_arch_unwindinfo_create (monoui);
1121         
1122         unwindinfo = (MonoUnwindInfo*)*monoui;
1123
1124         if (unwindinfo->unwindInfo.CountOfCodes >= MONO_MAX_UNWIND_CODES)
1125                 g_error ("Larger allocation needed for the unwind information.");
1126
1127         codeindex = MONO_MAX_UNWIND_CODES - (++unwindinfo->unwindInfo.CountOfCodes);
1128         unwindcode = &unwindinfo->unwindInfo.UnwindCode[codeindex];
1129         unwindcode->UnwindOp = 0; /*UWOP_PUSH_NONVOL*/
1130         unwindcode->CodeOffset = (((guchar*)nextip)-((guchar*)codebegin));
1131         unwindcode->OpInfo = reg;
1132
1133         if (unwindinfo->unwindInfo.SizeOfProlog >= unwindcode->CodeOffset)
1134                 g_error ("Adding unwind info in wrong order.");
1135         
1136         unwindinfo->unwindInfo.SizeOfProlog = unwindcode->CodeOffset;
1137 }
1138
1139 void
1140 mono_arch_unwindinfo_add_set_fpreg (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg )
1141 {
1142         PMonoUnwindInfo unwindinfo;
1143         PUNWIND_CODE unwindcode;
1144         guchar codeindex;
1145         if (!*monoui)
1146                 mono_arch_unwindinfo_create (monoui);
1147         
1148         unwindinfo = (MonoUnwindInfo*)*monoui;
1149
1150         if (unwindinfo->unwindInfo.CountOfCodes + 1 >= MONO_MAX_UNWIND_CODES)
1151                 g_error ("Larger allocation needed for the unwind information.");
1152
1153         codeindex = MONO_MAX_UNWIND_CODES - (unwindinfo->unwindInfo.CountOfCodes += 2);
1154         unwindcode = &unwindinfo->unwindInfo.UnwindCode[codeindex];
1155         unwindcode->FrameOffset = 0; /*Assuming no frame pointer offset for mono*/
1156         unwindcode++;
1157         unwindcode->UnwindOp = 3; /*UWOP_SET_FPREG*/
1158         unwindcode->CodeOffset = (((guchar*)nextip)-((guchar*)codebegin));
1159         unwindcode->OpInfo = reg;
1160         
1161         unwindinfo->unwindInfo.FrameRegister = reg;
1162
1163         if (unwindinfo->unwindInfo.SizeOfProlog >= unwindcode->CodeOffset)
1164                 g_error ("Adding unwind info in wrong order.");
1165         
1166         unwindinfo->unwindInfo.SizeOfProlog = unwindcode->CodeOffset;
1167 }
1168
1169 void
1170 mono_arch_unwindinfo_add_alloc_stack (gpointer* monoui, gpointer codebegin, gpointer nextip, guint size )
1171 {
1172         PMonoUnwindInfo unwindinfo;
1173         PUNWIND_CODE unwindcode;
1174         guchar codeindex;
1175         guchar codesneeded;
1176         if (!*monoui)
1177                 mono_arch_unwindinfo_create (monoui);
1178         
1179         unwindinfo = (MonoUnwindInfo*)*monoui;
1180
1181         if (size < 0x8)
1182                 g_error ("Stack allocation must be equal to or greater than 0x8.");
1183         
1184         if (size <= 0x80)
1185                 codesneeded = 1;
1186         else if (size <= 0x7FFF8)
1187                 codesneeded = 2;
1188         else
1189                 codesneeded = 3;
1190         
1191         if (unwindinfo->unwindInfo.CountOfCodes + codesneeded > MONO_MAX_UNWIND_CODES)
1192                 g_error ("Larger allocation needed for the unwind information.");
1193
1194         codeindex = MONO_MAX_UNWIND_CODES - (unwindinfo->unwindInfo.CountOfCodes += codesneeded);
1195         unwindcode = &unwindinfo->unwindInfo.UnwindCode[codeindex];
1196
1197         if (codesneeded == 1) {
1198                 /*The size of the allocation is 
1199                   (the number in the OpInfo member) times 8 plus 8*/
1200                 unwindcode->OpInfo = (size - 8)/8;
1201                 unwindcode->UnwindOp = 2; /*UWOP_ALLOC_SMALL*/
1202         }
1203         else {
1204                 if (codesneeded == 3) {
1205                         /*the unscaled size of the allocation is recorded
1206                           in the next two slots in little-endian format*/
1207                         *((unsigned int*)(&unwindcode->FrameOffset)) = size;
1208                         unwindcode += 2;
1209                         unwindcode->OpInfo = 1;
1210                 }
1211                 else {
1212                         /*the size of the allocation divided by 8
1213                           is recorded in the next slot*/
1214                         unwindcode->FrameOffset = size/8; 
1215                         unwindcode++;   
1216                         unwindcode->OpInfo = 0;
1217                         
1218                 }
1219                 unwindcode->UnwindOp = 1; /*UWOP_ALLOC_LARGE*/
1220         }
1221
1222         unwindcode->CodeOffset = (((guchar*)nextip)-((guchar*)codebegin));
1223
1224         if (unwindinfo->unwindInfo.SizeOfProlog >= unwindcode->CodeOffset)
1225                 g_error ("Adding unwind info in wrong order.");
1226         
1227         unwindinfo->unwindInfo.SizeOfProlog = unwindcode->CodeOffset;
1228 }
1229
1230 guint
1231 mono_arch_unwindinfo_get_size (gpointer monoui)
1232 {
1233         PMonoUnwindInfo unwindinfo;
1234         if (!monoui)
1235                 return 0;
1236         
1237         unwindinfo = (MonoUnwindInfo*)monoui;
1238         return (8 + sizeof (MonoUnwindInfo)) - 
1239                 (sizeof (UNWIND_CODE) * (MONO_MAX_UNWIND_CODES - unwindinfo->unwindInfo.CountOfCodes));
1240 }
1241
1242 PRUNTIME_FUNCTION
1243 MONO_GET_RUNTIME_FUNCTION_CALLBACK ( DWORD64 ControlPc, IN PVOID Context )
1244 {
1245         MonoJitInfo *ji;
1246         guint64 pos;
1247         PMonoUnwindInfo targetinfo;
1248         MonoDomain *domain = mono_domain_get ();
1249
1250         ji = mini_jit_info_table_find (domain, (char*)ControlPc, NULL);
1251         if (!ji)
1252                 return 0;
1253
1254         pos = (guint64)(((char*)ji->code_start) + ji->code_size);
1255         
1256         targetinfo = (PMonoUnwindInfo)ALIGN_TO (pos, 8);
1257
1258         targetinfo->runtimeFunction.UnwindData = ((DWORD64)&targetinfo->unwindInfo) - ((DWORD64)Context);
1259
1260         return &targetinfo->runtimeFunction;
1261 }
1262
1263 void
1264 mono_arch_unwindinfo_install_unwind_info (gpointer* monoui, gpointer code, guint code_size)
1265 {
1266         PMonoUnwindInfo unwindinfo, targetinfo;
1267         guchar codecount;
1268         guint64 targetlocation;
1269         if (!*monoui)
1270                 return;
1271
1272         unwindinfo = (MonoUnwindInfo*)*monoui;
1273         targetlocation = (guint64)&(((guchar*)code)[code_size]);
1274         targetinfo = (PMonoUnwindInfo) ALIGN_TO(targetlocation, 8);
1275
1276         unwindinfo->runtimeFunction.EndAddress = code_size;
1277         unwindinfo->runtimeFunction.UnwindData = ((guchar*)&targetinfo->unwindInfo) - ((guchar*)code);
1278         
1279         memcpy (targetinfo, unwindinfo, sizeof (MonoUnwindInfo) - (sizeof (UNWIND_CODE) * MONO_MAX_UNWIND_CODES));
1280         
1281         codecount = unwindinfo->unwindInfo.CountOfCodes;
1282         if (codecount) {
1283                 memcpy (&targetinfo->unwindInfo.UnwindCode[0], &unwindinfo->unwindInfo.UnwindCode[MONO_MAX_UNWIND_CODES-codecount], 
1284                         sizeof (UNWIND_CODE) * unwindinfo->unwindInfo.CountOfCodes);
1285         }
1286
1287         g_free (unwindinfo);
1288         *monoui = 0;
1289
1290         RtlInstallFunctionTableCallback (((DWORD64)code) | 0x3, (DWORD64)code, code_size, MONO_GET_RUNTIME_FUNCTION_CALLBACK, code, NULL);
1291 }
1292
1293 #endif
1294
1295 #if MONO_SUPPORT_TASKLETS
1296 MonoContinuationRestore
1297 mono_tasklets_arch_restore (void)
1298 {
1299         static guint8* saved = NULL;
1300         guint8 *code, *start;
1301         int cont_reg = AMD64_R9; /* register usable on both call conventions */
1302
1303         if (saved)
1304                 return (MonoContinuationRestore)saved;
1305         code = start = mono_global_codeman_reserve (64);
1306         /* the signature is: restore (MonoContinuation *cont, int state, MonoLMF **lmf_addr) */
1307         /* cont is in AMD64_ARG_REG1 ($rcx or $rdi)
1308          * state is in AMD64_ARG_REG2 ($rdx or $rsi)
1309          * lmf_addr is in AMD64_ARG_REG3 ($r8 or $rdx)
1310          * We move cont to cont_reg since we need both rcx and rdi for the copy
1311          * state is moved to $rax so it's setup as the return value and we can overwrite $rsi
1312          */
1313         amd64_mov_reg_reg (code, cont_reg, MONO_AMD64_ARG_REG1, 8);
1314         amd64_mov_reg_reg (code, AMD64_RAX, MONO_AMD64_ARG_REG2, 8);
1315         /* setup the copy of the stack */
1316         amd64_mov_reg_membase (code, AMD64_RCX, cont_reg, G_STRUCT_OFFSET (MonoContinuation, stack_used_size), sizeof (int));
1317         amd64_shift_reg_imm (code, X86_SHR, AMD64_RCX, 3);
1318         x86_cld (code);
1319         amd64_mov_reg_membase (code, AMD64_RSI, cont_reg, G_STRUCT_OFFSET (MonoContinuation, saved_stack), sizeof (gpointer));
1320         amd64_mov_reg_membase (code, AMD64_RDI, cont_reg, G_STRUCT_OFFSET (MonoContinuation, return_sp), sizeof (gpointer));
1321         amd64_prefix (code, X86_REP_PREFIX);
1322         amd64_movsl (code);
1323
1324         /* now restore the registers from the LMF */
1325         amd64_mov_reg_membase (code, AMD64_RCX, cont_reg, G_STRUCT_OFFSET (MonoContinuation, lmf), 8);
1326         amd64_mov_reg_membase (code, AMD64_RBX, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rbx), 8);
1327         amd64_mov_reg_membase (code, AMD64_RBP, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rbp), 8);
1328         amd64_mov_reg_membase (code, AMD64_R12, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, r12), 8);
1329         amd64_mov_reg_membase (code, AMD64_R13, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, r13), 8);
1330         amd64_mov_reg_membase (code, AMD64_R14, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, r14), 8);
1331         amd64_mov_reg_membase (code, AMD64_R15, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, r15), 8);
1332 #ifdef PLATFORM_WIN32
1333         amd64_mov_reg_membase (code, AMD64_RDI, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rdi), 8);
1334         amd64_mov_reg_membase (code, AMD64_RSI, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rsi), 8);
1335 #endif
1336         amd64_mov_reg_membase (code, AMD64_RSP, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rsp), 8);
1337
1338         /* restore the lmf chain */
1339         /*x86_mov_reg_membase (code, X86_ECX, X86_ESP, 12, 4);
1340         x86_mov_membase_reg (code, X86_ECX, 0, X86_EDX, 4);*/
1341
1342         /* state is already in rax */
1343         amd64_jump_membase (code, cont_reg, G_STRUCT_OFFSET (MonoContinuation, return_ip));
1344         g_assert ((code - start) <= 64);
1345         saved = start;
1346         return (MonoContinuationRestore)saved;
1347 }
1348 #endif
1349