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