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