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