1 /**
2 * \file
3 * exception support for ARM64
4 *
5 * Copyright 2013 Xamarin Inc
6 *
7 * Based on exceptions-arm.c:
8 *
9 * Authors:
10 * Dietmar Maurer (dietmar@ximian.com)
11 * Paolo Molaro (lupus@ximian.com)
12 *
13 * (C) 2001 Ximian, Inc.
14 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 */
16
17 #include "mini.h"
18 #include "mini-runtime.h"
19 #include "aot-runtime.h"
20
21 #include <mono/arch/arm64/arm64-codegen.h>
22 #include <mono/metadata/abi-details.h>
23
24 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
25
26 #ifndef DISABLE_JIT
27
28 gpointer
mono_arch_get_restore_context(MonoTrampInfo ** info,gboolean aot)29 mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
30 {
31 guint8 *start, *code;
32 MonoJumpInfo *ji = NULL;
33 GSList *unwind_ops = NULL;
34 int i, ctx_reg, size;
35 guint8 *labels [16];
36
37 size = 256;
38 code = start = mono_global_codeman_reserve (size);
39
40 arm_movx (code, ARMREG_IP0, ARMREG_R0);
41 ctx_reg = ARMREG_IP0;
42
43 /* Restore fregs */
44 arm_ldrx (code, ARMREG_IP1, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, has_fregs));
45 labels [0] = code;
46 arm_cbzx (code, ARMREG_IP1, 0);
47 for (i = 0; i < 32; ++i)
48 arm_ldrfpx (code, i, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, fregs) + (i * sizeof (MonoContextSimdReg)));
49 mono_arm_patch (labels [0], code, MONO_R_ARM64_CBZ);
50 /* Restore gregs */
51 // FIXME: Restore less registers
52 // FIXME: fp should be restored later
53 code = mono_arm_emit_load_regarray (code, 0xffffffff & ~(1 << ctx_reg) & ~(1 << ARMREG_SP), ctx_reg, MONO_STRUCT_OFFSET (MonoContext, regs));
54 /* ip0/ip1 doesn't need to be restored */
55 /* ip1 = pc */
56 arm_ldrx (code, ARMREG_IP1, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, pc));
57 /* ip0 = sp */
58 arm_ldrx (code, ARMREG_IP0, ctx_reg, MONO_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_SP * 8));
59 /* Restore sp, ctx is no longer valid */
60 arm_movspx (code, ARMREG_SP, ARMREG_IP0);
61 /* Branch to pc */
62 arm_brx (code, ARMREG_IP1);
63 /* Not reached */
64 arm_brk (code, 0);
65
66 g_assert ((code - start) < size);
67 mono_arch_flush_icache (start, code - start);
68 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL));
69
70 if (info)
71 *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops);
72
73 return start;
74 }
75
76 gpointer
mono_arch_get_call_filter(MonoTrampInfo ** info,gboolean aot)77 mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
78 {
79 guint8 *code;
80 guint8* start;
81 int i, size, offset, gregs_offset, fregs_offset, ctx_offset, num_fregs, frame_size;
82 MonoJumpInfo *ji = NULL;
83 GSList *unwind_ops = NULL;
84 guint8 *labels [16];
85
86 size = 512;
87 start = code = mono_global_codeman_reserve (size);
88
89 /* Compute stack frame size and offsets */
90 offset = 0;
91 /* frame block */
92 offset += 2 * 8;
93 /* gregs */
94 gregs_offset = offset;
95 offset += 32 * 8;
96 /* fregs */
97 num_fregs = 8;
98 fregs_offset = offset;
99 offset += num_fregs * 8;
100 ctx_offset = offset;
101 ctx_offset += 8;
102 frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
103
104 /*
105 * We are being called from C code, ctx is in r0, the address to call is in r1.
106 * We need to save state, restore ctx, make the call, then restore the previous state,
107 * returning the value returned by the call.
108 */
109
110 /* Setup a frame */
111 arm_stpx_pre (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, -frame_size);
112 arm_movspx (code, ARMREG_FP, ARMREG_SP);
113
114 /* Save ctx */
115 arm_strx (code, ARMREG_R0, ARMREG_FP, ctx_offset);
116 /* Save gregs */
117 code = mono_arm_emit_store_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS | (1 << ARMREG_FP), ARMREG_FP, gregs_offset);
118 /* Save fregs */
119 for (i = 0; i < num_fregs; ++i)
120 arm_strfpx (code, ARMREG_D8 + i, ARMREG_FP, fregs_offset + (i * 8));
121
122 /* Load regs from ctx */
123 code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, regs));
124 /* Load fregs */
125 arm_ldrx (code, ARMREG_IP0, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, has_fregs));
126 labels [0] = code;
127 arm_cbzx (code, ARMREG_IP0, 0);
128 for (i = 0; i < num_fregs; ++i)
129 arm_ldrfpx (code, ARMREG_D8 + i, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, fregs) + ((i + 8) * sizeof (MonoContextSimdReg)));
130 mono_arm_patch (labels [0], code, MONO_R_ARM64_CBZ);
131 /* Load fp */
132 arm_ldrx (code, ARMREG_FP, ARMREG_R0, MONO_STRUCT_OFFSET (MonoContext, regs) + (ARMREG_FP * 8));
133
134 /* Make the call */
135 arm_blrx (code, ARMREG_R1);
136 /* For filters, the result is in R0 */
137
138 /* Restore fp */
139 arm_ldrx (code, ARMREG_FP, ARMREG_SP, gregs_offset + (ARMREG_FP * 8));
140 /* Load ctx */
141 arm_ldrx (code, ARMREG_IP0, ARMREG_FP, ctx_offset);
142 /* Save registers back to ctx */
143 /* This isn't strictly neccessary since we don't allocate variables used in eh clauses to registers */
144 code = mono_arm_emit_store_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, ARMREG_IP0, MONO_STRUCT_OFFSET (MonoContext, regs));
145
146 /* Restore regs */
147 code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS, ARMREG_FP, gregs_offset);
148 /* Restore fregs */
149 for (i = 0; i < num_fregs; ++i)
150 arm_ldrfpx (code, ARMREG_D8 + i, ARMREG_FP, fregs_offset + (i * 8));
151 /* Destroy frame */
152 code = mono_arm_emit_destroy_frame (code, frame_size, (1 << ARMREG_IP0));
153 arm_retx (code, ARMREG_LR);
154
155 g_assert ((code - start) < size);
156 mono_arch_flush_icache (start, code - start);
157 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL));
158
159 if (info)
160 *info = mono_tramp_info_create ("call_filter", start, code - start, ji, unwind_ops);
161
162 return start;
163 }
164
165 static gpointer
get_throw_trampoline(int size,gboolean corlib,gboolean rethrow,gboolean llvm,gboolean resume_unwind,const char * tramp_name,MonoTrampInfo ** info,gboolean aot)166 get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm, gboolean resume_unwind, const char *tramp_name, MonoTrampInfo **info, gboolean aot)
167 {
168 guint8 *start, *code;
169 MonoJumpInfo *ji = NULL;
170 GSList *unwind_ops = NULL;
171 int i, offset, gregs_offset, fregs_offset, frame_size, num_fregs;
172
173 code = start = mono_global_codeman_reserve (size);
174
175 /* We are being called by JITted code, the exception object/type token is in R0 */
176
177 /* Compute stack frame size and offsets */
178 offset = 0;
179 /* frame block */
180 offset += 2 * 8;
181 /* gregs */
182 gregs_offset = offset;
183 offset += 32 * 8;
184 /* fregs */
185 num_fregs = 8;
186 fregs_offset = offset;
187 offset += num_fregs * 8;
188 frame_size = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
189
190 /* Setup a frame */
191 arm_stpx_pre (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, -frame_size);
192 arm_movspx (code, ARMREG_FP, ARMREG_SP);
193
194 /* Save gregs */
195 code = mono_arm_emit_store_regarray (code, 0xffffffff, ARMREG_FP, gregs_offset);
196 if (corlib && !llvm)
197 /* The real LR is in R1 */
198 arm_strx (code, ARMREG_R1, ARMREG_FP, gregs_offset + (ARMREG_LR * 8));
199 /* Save fp/sp */
200 arm_ldrx (code, ARMREG_IP0, ARMREG_FP, 0);
201 arm_strx (code, ARMREG_IP0, ARMREG_FP, gregs_offset + (ARMREG_FP * 8));
202 arm_addx_imm (code, ARMREG_IP0, ARMREG_FP, frame_size);
203 arm_strx (code, ARMREG_IP0, ARMREG_FP, gregs_offset + (ARMREG_SP * 8));
204 /* Save fregs */
205 for (i = 0; i < num_fregs; ++i)
206 arm_strfpx (code, ARMREG_D8 + i, ARMREG_FP, fregs_offset + (i * 8));
207
208 /* Call the C trampoline function */
209 /* Arg1 = exception object/type token */
210 arm_movx (code, ARMREG_R0, ARMREG_R0);
211 /* Arg2 = caller ip */
212 if (corlib) {
213 if (llvm)
214 arm_ldrx (code, ARMREG_R1, ARMREG_FP, gregs_offset + (ARMREG_LR * 8));
215 else
216 arm_movx (code, ARMREG_R1, ARMREG_R1);
217 } else {
218 arm_ldrx (code, ARMREG_R1, ARMREG_FP, 8);
219 }
220 /* Arg 3 = gregs */
221 arm_addx_imm (code, ARMREG_R2, ARMREG_FP, gregs_offset);
222 /* Arg 4 = fregs */
223 arm_addx_imm (code, ARMREG_R3, ARMREG_FP, fregs_offset);
224 /* Arg 5 = corlib */
225 arm_movzx (code, ARMREG_R4, corlib ? 1 : 0, 0);
226 /* Arg 6 = rethrow */
227 arm_movzx (code, ARMREG_R5, rethrow ? 1 : 0, 0);
228 /* Call the function */
229 if (aot) {
230 const char *icall_name;
231
232 if (resume_unwind)
233 icall_name = "mono_arm_resume_unwind";
234 else
235 icall_name = "mono_arm_throw_exception";
236
237 code = mono_arm_emit_aotconst (&ji, code, start, ARMREG_LR, MONO_PATCH_INFO_JIT_ICALL_ADDR, icall_name);
238 } else {
239 gpointer icall_func;
240
241 if (resume_unwind)
242 icall_func = mono_arm_resume_unwind;
243 else
244 icall_func = mono_arm_throw_exception;
245
246 code = mono_arm_emit_imm64 (code, ARMREG_LR, (guint64)icall_func);
247 }
248 arm_blrx (code, ARMREG_LR);
249 /* This shouldn't return */
250 arm_brk (code, 0x0);
251
252 g_assert ((code - start) < size);
253 mono_arch_flush_icache (start, code - start);
254 MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL));
255
256 if (info)
257 *info = mono_tramp_info_create (tramp_name, start, code - start, ji, unwind_ops);
258
259 return start;
260 }
261
262 gpointer
mono_arch_get_throw_exception(MonoTrampInfo ** info,gboolean aot)263 mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot)
264 {
265 return get_throw_trampoline (256, FALSE, FALSE, FALSE, FALSE, "throw_exception", info, aot);
266 }
267
268 gpointer
mono_arch_get_rethrow_exception(MonoTrampInfo ** info,gboolean aot)269 mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot)
270 {
271 return get_throw_trampoline (256, FALSE, TRUE, FALSE, FALSE, "rethrow_exception", info, aot);
272 }
273
274 gpointer
mono_arch_get_throw_corlib_exception(MonoTrampInfo ** info,gboolean aot)275 mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot)
276 {
277 return get_throw_trampoline (256, TRUE, FALSE, FALSE, FALSE, "throw_corlib_exception", info, aot);
278 }
279
280 GSList*
mono_arm_get_exception_trampolines(gboolean aot)281 mono_arm_get_exception_trampolines (gboolean aot)
282 {
283 MonoTrampInfo *info;
284 GSList *tramps = NULL;
285
286 /* LLVM uses the normal trampolines, but with a different name */
287 get_throw_trampoline (256, TRUE, FALSE, FALSE, FALSE, "llvm_throw_corlib_exception_trampoline", &info, aot);
288 tramps = g_slist_prepend (tramps, info);
289
290 get_throw_trampoline (256, TRUE, FALSE, TRUE, FALSE, "llvm_throw_corlib_exception_abs_trampoline", &info, aot);
291 tramps = g_slist_prepend (tramps, info);
292
293 get_throw_trampoline (256, FALSE, FALSE, FALSE, TRUE, "llvm_resume_unwind_trampoline", &info, aot);
294 tramps = g_slist_prepend (tramps, info);
295
296 return tramps;
297 }
298
299 #else /* DISABLE_JIT */
300
301 gpointer
mono_arch_get_restore_context(MonoTrampInfo ** info,gboolean aot)302 mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
303 {
304 g_assert_not_reached ();
305 return NULL;
306 }
307
308 gpointer
mono_arch_get_call_filter(MonoTrampInfo ** info,gboolean aot)309 mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
310 {
311 g_assert_not_reached ();
312 return NULL;
313 }
314
315 gpointer
mono_arch_get_throw_exception(MonoTrampInfo ** info,gboolean aot)316 mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot)
317 {
318 g_assert_not_reached ();
319 return NULL;
320 }
321
322 gpointer
mono_arch_get_rethrow_exception(MonoTrampInfo ** info,gboolean aot)323 mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot)
324 {
325 g_assert_not_reached ();
326 return NULL;
327 }
328
329 gpointer
mono_arch_get_throw_corlib_exception(MonoTrampInfo ** info,gboolean aot)330 mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot)
331 {
332 g_assert_not_reached ();
333 return NULL;
334 }
335
336 GSList*
mono_arm_get_exception_trampolines(gboolean aot)337 mono_arm_get_exception_trampolines (gboolean aot)
338 {
339 g_assert_not_reached ();
340 return NULL;
341 }
342
343 #endif /* !DISABLE_JIT */
344
345 void
mono_arch_exceptions_init(void)346 mono_arch_exceptions_init (void)
347 {
348 guint8 *tramp;
349 GSList *tramps, *l;
350
351 if (mono_aot_only) {
352 tramp = mono_aot_get_trampoline ("llvm_throw_corlib_exception_trampoline");
353 mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_trampoline", NULL, TRUE);
354 tramp = mono_aot_get_trampoline ("llvm_throw_corlib_exception_abs_trampoline");
355 mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_abs_trampoline", NULL, TRUE);
356 tramp = mono_aot_get_trampoline ("llvm_resume_unwind_trampoline");
357 mono_register_jit_icall (tramp, "llvm_resume_unwind_trampoline", NULL, TRUE);
358 } else {
359 tramps = mono_arm_get_exception_trampolines (FALSE);
360 for (l = tramps; l; l = l->next) {
361 MonoTrampInfo *info = l->data;
362
363 mono_register_jit_icall (info->code, g_strdup (info->name), NULL, TRUE);
364 mono_tramp_info_register (info, NULL);
365 }
366 g_slist_free (tramps);
367 }
368 }
369
370 /*
371 * mono_arm_throw_exception:
372 *
373 * This function is called by the exception trampolines.
374 * FP_REGS points to the 8 callee saved fp regs.
375 */
376 void
mono_arm_throw_exception(gpointer arg,mgreg_t pc,mgreg_t * int_regs,gdouble * fp_regs,gboolean corlib,gboolean rethrow)377 mono_arm_throw_exception (gpointer arg, mgreg_t pc, mgreg_t *int_regs, gdouble *fp_regs, gboolean corlib, gboolean rethrow)
378 {
379 MonoError error;
380 MonoContext ctx;
381 MonoObject *exc = NULL;
382 guint32 ex_token_index, ex_token;
383
384 if (!corlib)
385 exc = arg;
386 else {
387 ex_token_index = (guint64)arg;
388 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
389 exc = (MonoObject*)mono_exception_from_token (mono_defaults.corlib, ex_token);
390 }
391
392 /* Adjust pc so it points into the call instruction */
393 pc -= 4;
394
395 /* Initialize a ctx based on the arguments */
396 memset (&ctx, 0, sizeof (MonoContext));
397 memcpy (&(ctx.regs [0]), int_regs, sizeof (mgreg_t) * 32);
398 for (int i = 0; i < 8; i++)
399 *((gdouble*)&ctx.fregs [ARMREG_D8 + i]) = fp_regs [i];
400 ctx.has_fregs = 1;
401 ctx.pc = pc;
402
403 if (mono_object_isinst_checked (exc, mono_defaults.exception_class, &error)) {
404 MonoException *mono_ex = (MonoException*)exc;
405 if (!rethrow) {
406 mono_ex->stack_trace = NULL;
407 mono_ex->trace_ips = NULL;
408 }
409 }
410 mono_error_assert_ok (&error);
411
412 mono_handle_exception (&ctx, exc);
413
414 mono_restore_context (&ctx);
415 }
416
417 void
mono_arm_resume_unwind(gpointer arg,mgreg_t pc,mgreg_t * int_regs,gdouble * fp_regs,gboolean corlib,gboolean rethrow)418 mono_arm_resume_unwind (gpointer arg, mgreg_t pc, mgreg_t *int_regs, gdouble *fp_regs, gboolean corlib, gboolean rethrow)
419 {
420 MonoContext ctx;
421
422 /* Adjust pc so it points into the call instruction */
423 pc -= 4;
424
425 /* Initialize a ctx based on the arguments */
426 memset (&ctx, 0, sizeof (MonoContext));
427 memcpy (&(ctx.regs [0]), int_regs, sizeof (mgreg_t) * 32);
428 for (int i = 0; i < 8; i++)
429 *((gdouble*)&ctx.fregs [ARMREG_D8 + i]) = fp_regs [i];
430 ctx.has_fregs = 1;
431 ctx.pc = pc;
432
433 mono_resume_unwind (&ctx);
434 }
435
436 /*
437 * mono_arch_unwind_frame:
438 *
439 * See exceptions-amd64.c for docs;
440 */
441 gboolean
mono_arch_unwind_frame(MonoDomain * domain,MonoJitTlsData * jit_tls,MonoJitInfo * ji,MonoContext * ctx,MonoContext * new_ctx,MonoLMF ** lmf,mgreg_t ** save_locations,StackFrameInfo * frame)442 mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls,
443 MonoJitInfo *ji, MonoContext *ctx,
444 MonoContext *new_ctx, MonoLMF **lmf,
445 mgreg_t **save_locations,
446 StackFrameInfo *frame)
447 {
448 gpointer ip = MONO_CONTEXT_GET_IP (ctx);
449
450 memset (frame, 0, sizeof (StackFrameInfo));
451 frame->ji = ji;
452
453 *new_ctx = *ctx;
454
455 if (ji != NULL) {
456 mgreg_t regs [MONO_MAX_IREGS + 8 + 1];
457 guint8 *cfa;
458 guint32 unwind_info_len;
459 guint8 *unwind_info;
460
461 frame->type = FRAME_TYPE_MANAGED;
462
463 unwind_info = mono_jinfo_get_unwind_info (ji, &unwind_info_len);
464
465 memcpy (regs, &new_ctx->regs, sizeof (mgreg_t) * 32);
466 /* v8..v15 are callee saved */
467 for (int i = 0; i < 8; i++)
468 (regs + MONO_MAX_IREGS) [i] = *((mgreg_t*)&new_ctx->fregs [8 + i]);
469
470 mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start,
471 (guint8*)ji->code_start + ji->code_size,
472 ip, NULL, regs, MONO_MAX_IREGS + 8,
473 save_locations, MONO_MAX_IREGS, &cfa);
474
475 memcpy (&new_ctx->regs, regs, sizeof (mgreg_t) * 32);
476 for (int i = 0; i < 8; i++)
477 *((mgreg_t*)&new_ctx->fregs [8 + i]) = (regs + MONO_MAX_IREGS) [i];
478
479 new_ctx->pc = regs [ARMREG_LR];
480 new_ctx->regs [ARMREG_SP] = (mgreg_t)cfa;
481
482 if (*lmf && (*lmf)->gregs [MONO_ARCH_LMF_REG_SP] && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->gregs [MONO_ARCH_LMF_REG_SP])) {
483 /* remove any unused lmf */
484 *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
485 }
486
487 /* we substract 1, so that the IP points into the call instruction */
488 new_ctx->pc--;
489
490 return TRUE;
491 } else if (*lmf) {
492 g_assert ((((guint64)(*lmf)->previous_lmf) & 2) == 0);
493
494 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
495
496 ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->pc, NULL);
497 if (!ji)
498 return FALSE;
499
500 g_assert (MONO_ARCH_LMF_REGS == ((0x3ff << 19) | (1 << ARMREG_FP) | (1 << ARMREG_SP)));
501 memcpy (&new_ctx->regs [ARMREG_R19], &(*lmf)->gregs [0], sizeof (mgreg_t) * 10);
502 new_ctx->regs [ARMREG_FP] = (*lmf)->gregs [MONO_ARCH_LMF_REG_FP];
503 new_ctx->regs [ARMREG_SP] = (*lmf)->gregs [MONO_ARCH_LMF_REG_SP];
504 new_ctx->pc = (*lmf)->pc;
505
506 /* we substract 1, so that the IP points into the call instruction */
507 new_ctx->pc--;
508
509 *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
510
511 return TRUE;
512 }
513
514 return FALSE;
515 }
516
517 /*
518 * handle_exception:
519 *
520 * Called by resuming from a signal handler.
521 */
522 static void
handle_signal_exception(gpointer obj)523 handle_signal_exception (gpointer obj)
524 {
525 MonoJitTlsData *jit_tls = mono_tls_get_jit_tls ();
526 MonoContext ctx;
527
528 memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext));
529
530 mono_handle_exception (&ctx, obj);
531
532 mono_restore_context (&ctx);
533 }
534
535 /*
536 * This is the function called from the signal handler
537 */
538 gboolean
mono_arch_handle_exception(void * ctx,gpointer obj)539 mono_arch_handle_exception (void *ctx, gpointer obj)
540 {
541 #if defined(MONO_CROSS_COMPILE)
542 g_assert_not_reached ();
543 #else
544 MonoJitTlsData *jit_tls;
545 void *sigctx = ctx;
546
547 /*
548 * Resume into the normal stack and handle the exception there.
549 */
550 jit_tls = mono_tls_get_jit_tls ();
551
552 /* Pass the ctx parameter in TLS */
553 mono_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx);
554 /* The others in registers */
555 UCONTEXT_REG_R0 (sigctx) = (gsize)obj;
556
557 UCONTEXT_REG_PC (sigctx) = (gsize)handle_signal_exception;
558 UCONTEXT_REG_SP (sigctx) = UCONTEXT_REG_SP (sigctx) - MONO_ARCH_REDZONE_SIZE;
559 #endif
560
561 return TRUE;
562 }
563
564 gpointer
mono_arch_ip_from_context(void * sigctx)565 mono_arch_ip_from_context (void *sigctx)
566 {
567 #ifdef MONO_CROSS_COMPILE
568 g_assert_not_reached ();
569 return NULL;
570 #else
571 return (gpointer)UCONTEXT_REG_PC (sigctx);
572 #endif
573 }
574
575 void
mono_arch_setup_async_callback(MonoContext * ctx,void (* async_cb)(void * fun),gpointer user_data)576 mono_arch_setup_async_callback (MonoContext *ctx, void (*async_cb)(void *fun), gpointer user_data)
577 {
578 mgreg_t sp = (mgreg_t)MONO_CONTEXT_GET_SP (ctx);
579
580 // FIXME:
581 g_assert (!user_data);
582
583 /* Allocate a stack frame */
584 sp -= 32;
585 MONO_CONTEXT_SET_SP (ctx, sp);
586
587 mono_arch_setup_resume_sighandler_ctx (ctx, async_cb);
588 }
589
590 /*
591 * mono_arch_setup_resume_sighandler_ctx:
592 *
593 * Setup CTX so execution continues at FUNC.
594 */
595 void
mono_arch_setup_resume_sighandler_ctx(MonoContext * ctx,gpointer func)596 mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func)
597 {
598 MONO_CONTEXT_SET_IP (ctx,func);
599 }
600