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