2007-03-15 Jonathan Chambers <joncham@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/debug-helpers.h>
23 #include <mono/metadata/exception.h>
24 #include <mono/metadata/gc-internal.h>
25 #include <mono/metadata/mono-debug.h>
26
27 #include "mini.h"
28 #include "mini-amd64.h"
29
30 #define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
31
32 #ifdef PLATFORM_WIN32
33 static MonoW32ExceptionHandler fpe_handler;
34 static MonoW32ExceptionHandler ill_handler;
35 static MonoW32ExceptionHandler segv_handler;
36
37 static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
38
39 #define W32_SEH_HANDLE_EX(_ex) \
40         if (_ex##_handler) _ex##_handler((int)sctx)
41
42 /*
43  * Unhandled Exception Filter
44  * Top-level per-process exception handler.
45  */
46 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep)
47 {
48         EXCEPTION_RECORD* er;
49         CONTEXT* ctx;
50         MonoContext* sctx;
51         LONG res;
52
53         res = EXCEPTION_CONTINUE_EXECUTION;
54
55         er = ep->ExceptionRecord;
56         ctx = ep->ContextRecord;
57         sctx = g_malloc(sizeof(MonoContext));
58
59         /* Copy Win32 context to UNIX style context */
60         sctx->rax = ctx->Rax;
61         sctx->rbx = ctx->Rbx;
62         sctx->rcx = ctx->Rcx;
63         sctx->rdx = ctx->Rdx;
64         sctx->rbp = ctx->Rbp;
65         sctx->rsp = ctx->Rsp;
66         sctx->rsi = ctx->Rsi;
67         sctx->rdi = ctx->Rdi;
68         sctx->rip = ctx->Rip;
69         sctx->r12 = ctx->R12;
70         sctx->r13 = ctx->R13;
71         sctx->r14 = ctx->R14;
72         sctx->r15 = ctx->R15;
73
74         switch (er->ExceptionCode) {
75         case EXCEPTION_ACCESS_VIOLATION:
76                 W32_SEH_HANDLE_EX(segv);
77                 break;
78         case EXCEPTION_ILLEGAL_INSTRUCTION:
79                 W32_SEH_HANDLE_EX(ill);
80                 break;
81         case EXCEPTION_INT_DIVIDE_BY_ZERO:
82         case EXCEPTION_INT_OVERFLOW:
83         case EXCEPTION_FLT_DIVIDE_BY_ZERO:
84         case EXCEPTION_FLT_OVERFLOW:
85         case EXCEPTION_FLT_UNDERFLOW:
86         case EXCEPTION_FLT_INEXACT_RESULT:
87                 W32_SEH_HANDLE_EX(fpe);
88                 break;
89         default:
90                 break;
91         }
92
93         /* Copy context back */
94         ctx->Rax = sctx->rax;
95         ctx->Rbx = sctx->rbx;
96         ctx->Rcx = sctx->rcx;
97         ctx->Rdx = sctx->rdx;
98         ctx->Rbp = sctx->rbp;
99         ctx->Rsp = sctx->rsp;
100         ctx->Rsi = sctx->rsi;
101         ctx->Rdi = sctx->rdi;
102         ctx->Rip = sctx->rip;
103
104         g_free (sctx);
105
106         return res;
107 }
108
109 void win32_seh_init()
110 {
111         old_handler = SetUnhandledExceptionFilter(seh_handler);
112 }
113
114 void win32_seh_cleanup()
115 {
116         if (old_handler) SetUnhandledExceptionFilter(old_handler);
117 }
118
119 void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
120 {
121         switch (type) {
122         case SIGFPE:
123                 fpe_handler = handler;
124                 break;
125         case SIGILL:
126                 ill_handler = handler;
127                 break;
128         case SIGSEGV:
129                 segv_handler = handler;
130                 break;
131         default:
132                 break;
133         }
134 }
135
136 #endif /* PLATFORM_WIN32 */
137
138 /*
139  * mono_arch_get_restore_context:
140  *
141  * Returns a pointer to a method which restores a previously saved sigcontext.
142  */
143 gpointer
144 mono_arch_get_restore_context (void)
145 {
146         static guint8 *start = NULL;
147         static gboolean inited = FALSE;
148         guint8 *code;
149
150         if (inited)
151                 return start;
152
153         /* restore_contect (MonoContext *ctx) */
154
155         start = code = mono_global_codeman_reserve (256);
156
157         /* get return address */
158         amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RDI,  G_STRUCT_OFFSET (MonoContext, rip), 8);
159
160         /* Restore registers */
161         amd64_mov_reg_membase (code, AMD64_RBP, AMD64_RDI,  G_STRUCT_OFFSET (MonoContext, rbp), 8);
162         amd64_mov_reg_membase (code, AMD64_RBX, AMD64_RDI,  G_STRUCT_OFFSET (MonoContext, rbx), 8);
163         amd64_mov_reg_membase (code, AMD64_R12, AMD64_RDI,  G_STRUCT_OFFSET (MonoContext, r12), 8);
164         amd64_mov_reg_membase (code, AMD64_R13, AMD64_RDI,  G_STRUCT_OFFSET (MonoContext, r13), 8);
165         amd64_mov_reg_membase (code, AMD64_R14, AMD64_RDI,  G_STRUCT_OFFSET (MonoContext, r14), 8);
166         amd64_mov_reg_membase (code, AMD64_R15, AMD64_RDI,  G_STRUCT_OFFSET (MonoContext, r15), 8);
167
168         amd64_mov_reg_membase (code, AMD64_RSP, AMD64_RDI,  G_STRUCT_OFFSET (MonoContext, rsp), 8);
169
170         /* jump to the saved IP */
171         amd64_jump_reg (code, AMD64_RAX);
172
173         inited = TRUE;
174
175         return start;
176 }
177
178 /*
179  * mono_arch_get_call_filter:
180  *
181  * Returns a pointer to a method which calls an exception filter. We
182  * also use this function to call finally handlers (we pass NULL as 
183  * @exc object in this case).
184  */
185 gpointer
186 mono_arch_get_call_filter (void)
187 {
188         static guint8 *start;
189         static gboolean inited = FALSE;
190         int i;
191         guint8 *code;
192         guint32 pos;
193
194         if (inited)
195                 return start;
196
197         start = code = mono_global_codeman_reserve (64);
198
199         /* call_filter (MonoContext *ctx, unsigned long eip) */
200         code = start;
201
202         /* Alloc new frame */
203         amd64_push_reg (code, AMD64_RBP);
204         amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, 8);
205
206         /* Save callee saved regs */
207         pos = 0;
208         for (i = 0; i < AMD64_NREG; ++i)
209                 if (AMD64_IS_CALLEE_SAVED_REG (i)) {
210                         amd64_push_reg (code, i);
211                         pos += 8;
212                 }
213
214         /* Save EBP */
215         pos += 8;
216         amd64_push_reg (code, AMD64_RBP);
217
218         /* Make stack misaligned, the call will make it aligned again */
219         if (! (pos & 8))
220                 amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
221
222         /* set new EBP */
223         amd64_mov_reg_membase (code, AMD64_RBP, AMD64_RDI, G_STRUCT_OFFSET (MonoContext, rbp), 8);
224         /* load callee saved regs */
225         amd64_mov_reg_membase (code, AMD64_RBX, AMD64_RDI, G_STRUCT_OFFSET (MonoContext, rbx), 8);
226         amd64_mov_reg_membase (code, AMD64_R12, AMD64_RDI, G_STRUCT_OFFSET (MonoContext, r12), 8);
227         amd64_mov_reg_membase (code, AMD64_R13, AMD64_RDI, G_STRUCT_OFFSET (MonoContext, r13), 8);
228         amd64_mov_reg_membase (code, AMD64_R14, AMD64_RDI, G_STRUCT_OFFSET (MonoContext, r14), 8);
229         amd64_mov_reg_membase (code, AMD64_R15, AMD64_RDI, G_STRUCT_OFFSET (MonoContext, r15), 8);
230
231         /* call the handler */
232         amd64_call_reg (code, AMD64_RSI);
233
234         if (! (pos & 8))
235                 amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
236
237         /* restore RBP */
238         amd64_pop_reg (code, AMD64_RBP);
239
240         /* Restore callee saved regs */
241         for (i = AMD64_NREG; i >= 0; --i)
242                 if (AMD64_IS_CALLEE_SAVED_REG (i))
243                         amd64_pop_reg (code, i);
244
245         amd64_leave (code);
246         amd64_ret (code);
247
248         g_assert ((code - start) < 64);
249
250         inited = TRUE;
251
252         return start;
253 }
254
255 static void
256 throw_exception (MonoObject *exc, guint64 rip, guint64 rsp,
257                  guint64 rbx, guint64 rbp, guint64 r12, guint64 r13, 
258                  guint64 r14, guint64 r15, guint64 rethrow)
259 {
260         static void (*restore_context) (MonoContext *);
261         MonoContext ctx;
262
263         if (!restore_context)
264                 restore_context = mono_arch_get_restore_context ();
265
266         ctx.rsp = rsp;
267         ctx.rip = rip;
268         ctx.rbx = rbx;
269         ctx.rbp = rbp;
270         ctx.r12 = r12;
271         ctx.r13 = r13;
272         ctx.r14 = r14;
273         ctx.r15 = r15;
274
275         if (!rethrow && mono_debugger_throw_exception ((gpointer)(rip - 8), (gpointer)rsp, exc)) {
276                 /*
277                  * The debugger wants us to stop on the `throw' instruction.
278                  * By the time we get here, it already inserted a breakpoint on
279                  * eip - 8 (which is the address of the `mov %r15,%rdi ; callq throw').
280                  */
281
282                 /* FIXME FIXME
283                  *
284                  * In case of a rethrow, the JIT is emitting code like this:
285                  *
286                  *    mov    0xffffffffffffffd0(%rbp),%rax'
287                  *    mov    %rax,%rdi
288                  *    callq  throw
289                  *
290                  * Here, restore_context() wouldn't restore the %rax register correctly.
291                  */
292                 ctx.rip = rip - 8;
293                 ctx.rsp = rsp + 8;
294                 restore_context (&ctx);
295                 g_assert_not_reached ();
296         }
297
298         /* adjust eip so that it point into the call instruction */
299         ctx.rip -= 1;
300
301         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
302                 MonoException *mono_ex = (MonoException*)exc;
303                 if (!rethrow)
304                         mono_ex->stack_trace = NULL;
305         }
306         mono_handle_exception (&ctx, exc, (gpointer)rip, FALSE);
307         restore_context (&ctx);
308
309         g_assert_not_reached ();
310 }
311
312 static gpointer
313 get_throw_trampoline (gboolean rethrow)
314 {
315         guint8* start;
316         guint8 *code;
317
318         start = code = mono_global_codeman_reserve (64);
319
320         code = start;
321
322         /* Exception */
323         amd64_mov_reg_reg (code, AMD64_RDI, AMD64_RDI, 8);
324         /* IP */
325         amd64_mov_reg_membase (code, AMD64_RSI, AMD64_RSP, 0, 8);
326         /* SP */
327         amd64_lea_membase (code, AMD64_RDX, AMD64_RSP, 8);
328         /* Callee saved regs */
329         amd64_mov_reg_reg (code, AMD64_RCX, AMD64_RBX, 8);
330         amd64_mov_reg_reg (code, AMD64_R8, AMD64_RBP, 8);
331         amd64_mov_reg_reg (code, AMD64_R9, AMD64_R12, 8);
332         /* align stack */
333         amd64_push_imm (code, 0);
334         /* reverse order */
335         amd64_push_imm (code, rethrow);
336         amd64_push_reg (code, AMD64_R15);
337         amd64_push_reg (code, AMD64_R14);
338         amd64_push_reg (code, AMD64_R13);
339
340         amd64_mov_reg_imm (code, AMD64_R11, throw_exception);
341         amd64_call_reg (code, AMD64_R11);
342         amd64_breakpoint (code);
343
344         g_assert ((code - start) < 64);
345
346         return start;
347 }
348
349 /**
350  * mono_arch_get_throw_exception:
351  *
352  * Returns a function pointer which can be used to raise 
353  * exceptions. The returned function has the following 
354  * signature: void (*func) (MonoException *exc); 
355  *
356  */
357 gpointer 
358 mono_arch_get_throw_exception (void)
359 {
360         static guint8* start;
361         static gboolean inited = FALSE;
362
363         if (inited)
364                 return start;
365
366         start = get_throw_trampoline (FALSE);
367
368         inited = TRUE;
369
370         return start;
371 }
372
373 gpointer 
374 mono_arch_get_rethrow_exception (void)
375 {
376         static guint8* start;
377         static gboolean inited = FALSE;
378
379         if (inited)
380                 return start;
381
382         start = get_throw_trampoline (TRUE);
383
384         inited = TRUE;
385
386         return start;
387 }
388
389 gpointer 
390 mono_arch_get_throw_exception_by_name (void)
391 {       
392         static guint8* start;
393         static gboolean inited = FALSE;
394         guint8 *code;
395
396         if (inited)
397                 return start;
398
399         start = code = mono_global_codeman_reserve (64);
400
401         /* Not used on amd64 */
402         amd64_breakpoint (code);
403
404         return start;
405 }
406
407 /**
408  * mono_arch_get_throw_corlib_exception:
409  *
410  * Returns a function pointer which can be used to raise 
411  * corlib exceptions. The returned function has the following 
412  * signature: void (*func) (guint32 ex_token, guint32 offset); 
413  * Here, offset is the offset which needs to be substracted from the caller IP 
414  * to get the IP of the throw. Passing the offset has the advantage that it 
415  * needs no relocations in the caller.
416  */
417 gpointer 
418 mono_arch_get_throw_corlib_exception (void)
419 {
420         static guint8* start;
421         static gboolean inited = FALSE;
422         guint8 *code;
423         guint64 throw_ex;
424
425         if (inited)
426                 return start;
427
428         start = code = mono_global_codeman_reserve (64);
429
430         /* Push throw_ip */
431         amd64_push_reg (code, AMD64_RSI);
432
433         /* Call exception_from_token */
434         amd64_mov_reg_reg (code, AMD64_RSI, AMD64_RDI, 8);
435         amd64_mov_reg_imm (code, AMD64_RDI, mono_defaults.exception_class->image);
436         amd64_mov_reg_imm (code, AMD64_R11, mono_exception_from_token);
437         amd64_call_reg (code, AMD64_R11);
438
439         /* Compute throw_ip */
440         amd64_pop_reg (code, AMD64_RSI);
441         /* return addr */
442         amd64_pop_reg (code, AMD64_RDX);
443         amd64_alu_reg_reg (code, X86_SUB, AMD64_RDX, AMD64_RSI);
444
445         /* Put the throw_ip at the top of the misaligned stack */
446         amd64_push_reg (code, AMD64_RDX);
447
448         throw_ex = (guint64)mono_arch_get_throw_exception ();
449
450         /* Call throw_exception */
451         amd64_mov_reg_reg (code, AMD64_RDI, AMD64_RAX, 8);
452         amd64_mov_reg_imm (code, AMD64_R11, throw_ex);
453         /* The original IP is on the stack */
454         amd64_jump_reg (code, AMD64_R11);
455
456         g_assert ((code - start) < 64);
457
458         inited = TRUE;
459
460         return start;
461 }
462
463 /* mono_arch_find_jit_info:
464  *
465  * This function is used to gather information from @ctx. It return the 
466  * MonoJitInfo of the corresponding function, unwinds one stack frame and
467  * stores the resulting context into @new_ctx. It also stores a string 
468  * describing the stack location into @trace (if not NULL), and modifies
469  * the @lmf if necessary. @native_offset return the IP offset from the 
470  * start of the function or -1 if that info is not available.
471  */
472 MonoJitInfo *
473 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
474                          MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
475                          gboolean *managed)
476 {
477         MonoJitInfo *ji;
478         int i;
479         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
480
481         /* Avoid costly table lookup during stack overflow */
482         if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
483                 ji = prev_ji;
484         else
485                 ji = mono_jit_info_table_find (domain, ip);
486
487         if (managed)
488                 *managed = FALSE;
489
490         if (ji != NULL) {
491                 int offset;
492                 gboolean omit_fp = (ji->used_regs & (1 << 31)) > 0;
493
494                 *new_ctx = *ctx;
495
496                 if (managed)
497                         if (!ji->method->wrapper_type)
498                                 *managed = TRUE;
499
500                 /*
501                  * Some managed methods like pinvoke wrappers might have save_lmf set.
502                  * In this case, register save/restore code is not generated by the 
503                  * JIT, so we have to restore callee saved registers from the lmf.
504                  */
505                 if (ji->method->save_lmf) {
506                         /* 
507                          * We only need to do this if the exception was raised in managed
508                          * code, since otherwise the lmf was already popped of the stack.
509                          */
510                         if (*lmf && ((*lmf) != jit_tls->first_lmf) && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->rsp)) {
511                                 new_ctx->rbp = (*lmf)->ebp;
512                                 new_ctx->rbx = (*lmf)->rbx;
513                                 new_ctx->rsp = (*lmf)->rsp;
514                                 new_ctx->r12 = (*lmf)->r12;
515                                 new_ctx->r13 = (*lmf)->r13;
516                                 new_ctx->r14 = (*lmf)->r14;
517                                 new_ctx->r15 = (*lmf)->r15;
518                         }
519                 }
520                 else {
521                         offset = omit_fp ? 0 : -1;
522                         /* restore caller saved registers */
523                         for (i = 0; i < AMD64_NREG; i ++)
524                                 if (AMD64_IS_CALLEE_SAVED_REG (i) && (ji->used_regs & (1 << i))) {
525                                         guint64 reg;
526
527                                         if (omit_fp) {
528                                                 reg = *((guint64*)ctx->rsp + offset);
529                                                 offset ++;
530                                         }
531                                         else {
532                                                 reg = *((guint64 *)ctx->rbp + offset);
533                                                 offset --;
534                                         }
535
536                                         switch (i) {
537                                         case AMD64_RBX:
538                                                 new_ctx->rbx = reg;
539                                                 break;
540                                         case AMD64_R12:
541                                                 new_ctx->r12 = reg;
542                                                 break;
543                                         case AMD64_R13:
544                                                 new_ctx->r13 = reg;
545                                                 break;
546                                         case AMD64_R14:
547                                                 new_ctx->r14 = reg;
548                                                 break;
549                                         case AMD64_R15:
550                                                 new_ctx->r15 = reg;
551                                                 break;
552                                         case AMD64_RBP:
553                                                 new_ctx->rbp = reg;
554                                                 break;
555                                         default:
556                                                 g_assert_not_reached ();
557                                         }
558                                 }
559                 }
560
561                 if (*lmf && ((*lmf) != jit_tls->first_lmf) && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->rsp)) {
562                         /* remove any unused lmf */
563                         *lmf = (*lmf)->previous_lmf;
564                 }
565
566                 if (omit_fp) {
567                         /* Pop frame */
568                         new_ctx->rsp += (ji->used_regs >> 16) & (0x7fff);
569                         new_ctx->rip = *((guint64 *)new_ctx->rsp) - 1;
570                         /* Pop return address */
571                         new_ctx->rsp += 8;
572                 }
573                 else {
574                         /* Pop EBP and the return address */
575                         new_ctx->rsp = ctx->rbp + (2 * sizeof (gpointer));
576                         /* we substract 1, so that the IP points into the call instruction */
577                         new_ctx->rip = *((guint64 *)ctx->rbp + 1) - 1;
578                         new_ctx->rbp = *((guint64 *)ctx->rbp);
579                 }
580
581                 /* Pop arguments off the stack */
582                 {
583                         MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (ji->method)->param_count + 1);
584
585                         guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (ji->method), mono_method_signature (ji->method)->param_count, arg_info);
586                         new_ctx->rsp += stack_to_pop;
587                 }
588
589                 return ji;
590         } else if (*lmf) {
591                 
592                 *new_ctx = *ctx;
593
594                 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->rip))) {
595                 } else {
596                         if (!(*lmf)->method)
597                                 /* Top LMF entry */
598                                 return (gpointer)-1;
599                         /* Trampoline lmf frame */
600                         memset (res, 0, sizeof (MonoJitInfo));
601                         res->method = (*lmf)->method;
602                 }
603
604                 new_ctx->rip = (*lmf)->rip;
605                 new_ctx->rbp = (*lmf)->ebp;
606                 new_ctx->rsp = (*lmf)->rsp;
607
608                 new_ctx->rbx = (*lmf)->rbx;
609                 new_ctx->r12 = (*lmf)->r12;
610                 new_ctx->r13 = (*lmf)->r13;
611                 new_ctx->r14 = (*lmf)->r14;
612                 new_ctx->r15 = (*lmf)->r15;
613
614                 *lmf = (*lmf)->previous_lmf;
615
616                 return ji ? ji : res;
617         }
618
619         return NULL;
620 }
621
622 /**
623  * mono_arch_handle_exception:
624  *
625  * @ctx: saved processor state
626  * @obj: the exception object
627  */
628 gboolean
629 mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
630 {
631         MonoContext mctx;
632
633         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
634
635         mono_handle_exception (&mctx, obj, MONO_CONTEXT_GET_IP (&mctx), test_only);
636
637         mono_arch_monoctx_to_sigctx (&mctx, sigctx);
638
639         return TRUE;
640 }
641
642 #ifdef MONO_ARCH_USE_SIGACTION
643 static inline guint64*
644 gregs_from_ucontext (ucontext_t *ctx)
645 {
646 #ifdef __FreeBSD__
647     guint64 *gregs = (guint64 *) &ctx->uc_mcontext;
648 #else
649     guint64 *gregs = (guint64 *) &ctx->uc_mcontext.gregs;
650 #endif
651
652         return gregs;
653 }
654 #endif
655 void
656 mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
657 {
658 #ifdef MONO_ARCH_USE_SIGACTION
659         ucontext_t *ctx = (ucontext_t*)sigctx;
660
661     guint64 *gregs = gregs_from_ucontext (ctx);
662
663         mctx->rax = gregs [REG_RAX];
664         mctx->rbx = gregs [REG_RBX];
665         mctx->rcx = gregs [REG_RCX];
666         mctx->rdx = gregs [REG_RDX];
667         mctx->rbp = gregs [REG_RBP];
668         mctx->rsp = gregs [REG_RSP];
669         mctx->rsi = gregs [REG_RSI];
670         mctx->rdi = gregs [REG_RDI];
671         mctx->rip = gregs [REG_RIP];
672         mctx->r12 = gregs [REG_R12];
673         mctx->r13 = gregs [REG_R13];
674         mctx->r14 = gregs [REG_R14];
675         mctx->r15 = gregs [REG_R15];
676 #else
677         MonoContext *ctx = (MonoContext *)sigctx;
678
679         mctx->rax = ctx->rax;
680         mctx->rbx = ctx->rbx;
681         mctx->rcx = ctx->rcx;
682         mctx->rdx = ctx->rdx;
683         mctx->rbp = ctx->rbp;
684         mctx->rsp = ctx->rsp;
685         mctx->rsi = ctx->rsi;
686         mctx->rdi = ctx->rdi;
687         mctx->rip = ctx->rip;
688         mctx->r12 = ctx->r12;
689         mctx->r13 = ctx->r13;
690         mctx->r14 = ctx->r14;
691         mctx->r15 = ctx->r15;
692 #endif
693 }
694
695 void
696 mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
697 {
698 #ifdef MONO_ARCH_USE_SIGACTION
699         ucontext_t *ctx = (ucontext_t*)sigctx;
700
701     guint64 *gregs = gregs_from_ucontext (ctx);
702
703         gregs [REG_RAX] = mctx->rax;
704         gregs [REG_RBX] = mctx->rbx;
705         gregs [REG_RCX] = mctx->rcx;
706         gregs [REG_RDX] = mctx->rdx;
707         gregs [REG_RBP] = mctx->rbp;
708         gregs [REG_RSP] = mctx->rsp;
709         gregs [REG_RSI] = mctx->rsi;
710         gregs [REG_RDI] = mctx->rdi;
711         gregs [REG_RIP] = mctx->rip;
712         gregs [REG_R12] = mctx->r12;
713         gregs [REG_R13] = mctx->r13;
714         gregs [REG_R14] = mctx->r14;
715         gregs [REG_R15] = mctx->r15;
716 #else
717         MonoContext *ctx = (MonoContext *)sigctx;
718
719         ctx->rax = mctx->rax;
720         ctx->rbx = mctx->rbx;
721         ctx->rcx = mctx->rcx;
722         ctx->rdx = mctx->rdx;
723         ctx->rbp = mctx->rbp;
724         ctx->rsp = mctx->rsp;
725         ctx->rsi = mctx->rsi;
726         ctx->rdi = mctx->rdi;
727         ctx->rip = mctx->rip;
728         ctx->r12 = mctx->r12;
729         ctx->r13 = mctx->r13;
730         ctx->r14 = mctx->r14;
731         ctx->r15 = mctx->r15;
732 #endif
733 }
734
735 gpointer
736 mono_arch_ip_from_context (void *sigctx)
737 {
738         
739 #ifdef MONO_ARCH_USE_SIGACTION
740
741         ucontext_t *ctx = (ucontext_t*)sigctx;
742
743     guint64 *gregs = gregs_from_ucontext (ctx);
744
745         return (gpointer)gregs [REG_RIP];
746 #else
747         MonoContext *ctx = sigctx;
748         return (gpointer)ctx->rip;
749 #endif  
750 }
751