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