32a81b20b23c162e9d85c7a79dce0b23dab5dfab
[mono.git] / mono / mini / exceptions-sparc.c
1 /*
2  * exceptions-sparc.c: exception support for 64 bit sparc
3  *
4  * Authors:
5  *   Mark Crichton (crichton@gimp.org)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2003 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <glib.h>
13 #include <signal.h>
14 #include <string.h>
15 #include <sys/ucontext.h>
16
17 #include <mono/arch/sparc/sparc-codegen.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/tabledefs.h>
20 #include <mono/metadata/threads.h>
21 #include <mono/metadata/debug-helpers.h>
22 #include <mono/metadata/exception.h>
23 #include <mono/metadata/mono-debug.h>
24 #include <mono/metadata/gc-internal.h>
25
26 #include "mini.h"
27 #include "mini-sparc.h"
28
29 typedef struct MonoContext {
30         guint32 ip;
31         guint32 *sp;
32         guint32 *fp;
33 } MonoContext;
34
35 gboolean  mono_sparc_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only);
36
37 #define MONO_CONTEXT_SET_IP(ctx,eip) do { (ctx)->ip = (long)(eip); } while (0); 
38 #define MONO_CONTEXT_SET_BP(ctx,ebp) do { (ctx)->fp = (long)(ebp); } while (0); 
39
40 #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->ip))
41 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->fp))
42
43 #define IS_ON_SIGALTSTACK(jit_tls) FALSE
44
45 /*
46  * arch_get_restore_context:
47  *
48  * Returns a pointer to a method which restores a previously saved sigcontext.
49  */
50 static gpointer
51 arch_get_restore_context (void)
52 {
53         static guint32 start [32];
54         static int inited = 0;
55         guint32 *code;
56
57         if (inited)
58                 return start;
59
60         code = start;
61
62         sparc_ld_imm (code, sparc_o0, G_STRUCT_OFFSET (MonoContext, ip), sparc_i7);
63         sparc_ld_imm (code, sparc_o0, G_STRUCT_OFFSET (MonoContext, sp), sparc_i6);
64
65         sparc_jmpl_imm (code, sparc_i7, 0, sparc_g0);
66         /* FIXME: This does not return to the correct window */
67         sparc_restore_imm (code, sparc_g0, 0, sparc_g0);
68
69         g_assert ((code - start) < 32);
70
71         inited = 1;
72
73         return start;
74 }
75
76 /*
77  * arch_get_call_filter:
78  *
79  * Returns a pointer to a method which calls an exception filter. We
80  * also use this function to call finally handlers (we pass NULL as 
81  * @exc object in this case).
82  *
83  * call_filter (MonoContext *ctx, gpointer ip)
84  */
85 static gpointer
86 arch_get_call_filter (void)
87 {
88         static guint32 start [64];
89         static int inited = 0;
90         guint32 *code;
91         int i;
92
93         if (inited)
94                 return start;
95
96         code = start;
97
98         /*
99          * There are two frames here:
100          * - the first frame is used by call_filter
101          * - the second frame is used to run the filter code
102          */
103
104         /* Create first frame */
105         sparc_save_imm (code, sparc_sp, -160, sparc_sp);
106
107         sparc_mov_reg_reg (code, sparc_i1, sparc_o0);
108         sparc_ld_imm (code, sparc_i0, G_STRUCT_OFFSET (MonoContext, sp), sparc_o1);
109
110         /* Create second frame */
111         sparc_save_imm (code, sparc_sp, -160, sparc_sp);
112
113         sparc_mov_reg_reg (code, sparc_i0, sparc_o0);
114         sparc_mov_reg_reg (code, sparc_i1, sparc_o1);
115
116         /*
117          * We need to change %fp to point to the stack frame of the method
118          * containing the filter. But changing %fp also changes the %sp of
119          * the parent frame (the first frame), so if the OS saves the first frame,
120          * it saves it to the stack frame of the method, which is not good.
121          * So flush all register windows to memory before changing %fp.
122          */
123         sparc_flushw (code);
124
125         sparc_mov_reg_reg (code, sparc_fp, sparc_o7);
126
127         /* 
128          * Modify the second frame so it is identical to the one used in the
129          * method containing the filter.
130          */
131         for (i = 0; i < 16; ++i)
132                 sparc_ld_imm (code, sparc_o1, i * 4, sparc_l0 + i);
133
134         /* Save %fp to a location reserved in mono_arch_allocate_vars */
135         sparc_st_imm (code, sparc_o7, sparc_fp, -4);
136
137         /* Call the filter code, after this returns, %o0 will hold the result */
138         sparc_call_imm (code, sparc_o0, 0);
139         sparc_nop (code);
140
141         /* Restore original %fp */
142         sparc_ld_imm (code, sparc_fp, -4, sparc_fp);
143
144         sparc_mov_reg_reg (code, sparc_o0, sparc_i0);
145
146         /* Return to first frame */
147         sparc_restore (code, sparc_g0, sparc_g0, sparc_g0);
148
149         /* FIXME: Save locals to the stack */
150
151         /* Return to caller */
152         sparc_ret (code);
153         /* Return result in delay slot */
154         sparc_restore (code, sparc_o0, sparc_g0, sparc_o0);
155
156         g_assert ((code - start) < 64);
157
158         inited = 1;
159
160         return start;
161 }
162
163 static void
164 throw_exception (MonoObject *ex, guint32 sp, guint32 ip)
165 {
166         MonoContext ctx;
167         static void (*restore_context) (MonoContext *);
168
169         if (!restore_context)
170                 restore_context = arch_get_restore_context ();
171
172         ctx.sp = (guint32*)sp;
173         ctx.ip = ip;
174         ctx.fp = (guint32*)ctx.sp [sparc_i6 - 16];
175
176         mono_sparc_handle_exception (&ctx, ex, FALSE);
177         restore_context (&ctx);
178
179         g_assert_not_reached ();
180 }
181
182 /**
183  * arch_get_throw_exception_by_name:
184  *
185  * Returns a function pointer which can be used to raise exceptions.
186  * The returned function has the following 
187  * signature: void (*func) (char *exc_name); 
188  */
189 gpointer 
190 mono_arch_get_throw_exception (void)
191 {
192         static guint32 start [32];
193         static int inited = 0;
194         guint32 *code;
195
196         if (inited)
197                 return start;
198
199         inited = 1;
200         code = start;
201
202         sparc_save_imm (code, sparc_sp, -160, sparc_sp);
203
204         sparc_flushw (code);
205         sparc_mov_reg_reg (code, sparc_i0, sparc_o0);
206         sparc_mov_reg_reg (code, sparc_fp, sparc_o1);
207         sparc_mov_reg_reg (code, sparc_i7, sparc_o2);
208         sparc_set (code, throw_exception, sparc_o7);
209         sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite);
210         sparc_nop (code);
211
212         g_assert ((code - start) < 32);
213
214         return start;
215 }
216
217 /**
218  * arch_get_throw_exception_by_name:
219  *
220  * Returns a function pointer which can be used to raise 
221  * corlib exceptions. The returned function has the following 
222  * signature: void (*func) (char *exc_name, gpointer ip); 
223  */
224 gpointer 
225 mono_arch_get_throw_exception_by_name (void)
226 {
227         static guint32 start [32];
228         static int inited = 0;
229         guint32 *code;
230
231         if (inited)
232                 return start;
233
234         inited = 1;
235         code = start;
236
237         sparc_save_imm (code, sparc_sp, -160, sparc_sp);
238
239         sparc_mov_reg_reg (code, sparc_i0, sparc_o2);
240         sparc_set (code, mono_defaults.corlib, sparc_o0);
241         sparc_set (code, "System", sparc_o1);
242         sparc_set (code, mono_exception_from_name, sparc_o7);
243         sparc_jmpl (code, sparc_o7, sparc_g0, sparc_callsite);
244         sparc_nop (code);
245
246         /* Return to the caller, so exception handling does not see this frame */
247         sparc_restore (code, sparc_o0, sparc_g0, sparc_o0);
248
249         /* Put original return address into %o7 */
250         sparc_mov_reg_reg (code, sparc_o1, sparc_o7);
251         sparc_set (code, mono_arch_get_throw_exception (), sparc_g1);
252         /* Use a jmp instead of a call so o7 is preserved */
253         sparc_jmpl_imm (code, sparc_g1, 0, sparc_g0);
254         sparc_nop (code);
255
256         g_assert ((code - start) < 32);
257
258         return start;
259 }       
260
261 /* mono_arch_find_jit_info:
262  *
263  * This function is used to gather information from @ctx. It return the 
264  * MonoJitInfo of the corresponding function, unwinds one stack frame and
265  * stores the resulting context into @new_ctx. It also stores a string 
266  * describing the stack location into @trace (if not NULL), and modifies
267  * the @lmf if necessary. @native_offset return the IP offset from the 
268  * start of the function or -1 if that info is not available.
269  */
270 static MonoJitInfo *
271 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
272                          MonoContext *new_ctx, char **trace, MonoLMF **lmf, int *native_offset,
273                          gboolean *managed)
274 {
275         MonoJitInfo *ji;
276         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
277         guint32 *window;
278
279         /* Avoid costly table lookup during stack overflow */
280         if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
281                 ji = prev_ji;
282         else
283                 ji = mono_jit_info_table_find (domain, ip);
284
285         if (trace)
286                 *trace = NULL;
287
288         if (native_offset)
289                 *native_offset = -1;
290
291         if (managed)
292                 *managed = FALSE;
293
294         if (ji != NULL) {
295                 char *source_location, *tmpaddr, *fname;
296                 gint32 address, iloffset;
297
298                 *new_ctx = *ctx;
299
300                 address = (char *)ip - (char *)ji->code_start;
301
302                 if (native_offset)
303                         *native_offset = address;
304
305                 if (managed)
306                         if (!ji->method->wrapper_type)
307                                 *managed = TRUE;
308
309                 if (trace) {
310                         source_location = mono_debug_source_location_from_address (ji->method, address, NULL, domain);
311                         iloffset = mono_debug_il_offset_from_address (ji->method, address, domain);
312
313                         if (iloffset < 0)
314                                 tmpaddr = g_strdup_printf ("<0x%05x>", address);
315                         else
316                                 tmpaddr = g_strdup_printf ("[0x%05x]", iloffset);
317                 
318                         fname = mono_method_full_name (ji->method, TRUE);
319
320                         if (source_location)
321                                 *trace = g_strdup_printf ("in %s (at %s) %s", tmpaddr, source_location, fname);
322                         else
323                                 *trace = g_strdup_printf ("in %s %s", tmpaddr, fname);
324
325                         g_free (fname);
326                         g_free (source_location);
327                         g_free (tmpaddr);
328                 }
329
330                 /* FIXME: lmf */
331
332                 /* Restore ip and sp from the saved register window */
333                 window = (guint32*)ctx->sp;
334                 new_ctx->ip = window [sparc_i7 - 16];
335                 new_ctx->sp = (guint32*)(window [sparc_i6 - 16]);
336                 new_ctx->fp = (guint32*)(new_ctx->sp [sparc_i6 - 16]);
337
338                 *res = *ji;
339                 return res;
340         }
341         else {
342                 if (!(*lmf))
343                         return NULL;
344
345                 *new_ctx = *ctx;
346
347                 if (!(*lmf)->method)
348                         return (gpointer)-1;
349
350                 if (trace)
351                         *trace = g_strdup_printf ("in (unmanaged) %s", mono_method_full_name ((*lmf)->method, TRUE));
352                 
353                 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->ip))) {
354                         *res = *ji;
355                 } else {
356                         memset (res, 0, sizeof (MonoJitInfo));
357                         res->method = (*lmf)->method;
358                 }
359
360                 new_ctx->ip = (*lmf)->ip;
361                 new_ctx->sp = (*lmf)->sp;
362                 new_ctx->fp = (*lmf)->ebp;
363
364                 *lmf = (*lmf)->previous_lmf;
365
366                 return res;
367         }
368 }
369
370 gboolean
371 mono_arch_has_unwind_info (gconstpointer addr)
372 {
373         return FALSE;
374 }
375
376 static MonoArray *
377 glist_to_array (GList *list) 
378 {
379         MonoDomain *domain = mono_domain_get ();
380         MonoArray *res;
381         int len, i;
382
383         if (!list)
384                 return NULL;
385
386         len = g_list_length (list);
387         res = mono_array_new (domain, mono_defaults.int_class, len);
388
389         for (i = 0; list; list = list->next, i++)
390                 mono_array_set (res, gpointer, i, list->data);
391
392         return res;
393 }
394
395 MonoArray *
396 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
397 {
398         return NULL;
399 }
400
401 void
402 mono_jit_walk_stack (MonoStackWalk func, gpointer user_data)
403 {
404         MonoDomain *domain = mono_domain_get ();
405         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
406         MonoLMF *lmf = jit_tls->lmf;
407         MonoJitInfo *ji, rji;
408         gint native_offset, il_offset;
409         gboolean managed;
410
411         MonoContext ctx, new_ctx;
412
413         mono_sparc_flushw ();
414
415         MONO_CONTEXT_SET_IP (&ctx, __builtin_return_address (0));
416         MONO_CONTEXT_SET_BP (&ctx, __builtin_frame_address (0));
417
418         while (MONO_CONTEXT_GET_BP (&ctx) < jit_tls->end_of_stack) {
419                 
420                 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, NULL, &ctx, &new_ctx, NULL, &lmf, &native_offset, &managed);
421                 g_assert (ji);
422
423                 if (ji == (gpointer)-1)
424                         return;
425
426                 il_offset = mono_debug_il_offset_from_address (ji->method, native_offset, domain);
427
428                 if (func (ji->method, native_offset, il_offset, managed, user_data))
429                         return;
430                 
431                 ctx = new_ctx;
432         }
433 }
434
435 MonoBoolean
436 ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, 
437                           MonoReflectionMethod **method, 
438                           gint32 *iloffset, gint32 *native_offset,
439                           MonoString **file, gint32 *line, gint32 *column)
440 {
441         return FALSE;
442 }
443
444 /**
445  * mono_sparc_handle_exception:
446  * @ctx: saved processor state
447  * @obj: the exception object
448  * @test_only: only test if the exception is caught, but dont call handlers
449  *
450  *
451  */
452 gboolean
453 mono_sparc_handle_exception (MonoContext *ctx, gpointer obj, gboolean test_only)
454 {
455         MonoDomain *domain = mono_domain_get ();
456         MonoJitInfo *ji, rji;
457         static int (*call_filter) (MonoContext *, gpointer) = NULL;
458         static void (*restore_context) (MonoContext *);
459         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
460         MonoLMF *lmf = jit_tls->lmf;            
461         GList *trace_ips = NULL;
462         MonoException *mono_ex;
463         gboolean stack_overflow = FALSE;
464         MonoContext initial_ctx;
465         int frame_count = 0;
466         gboolean gc_disabled = FALSE;
467
468         /*
469          * This function might execute on an alternate signal stack, and Boehm GC
470          * can't handle that.
471          * Also, since the altstack is small, stack space intensive operations like
472          * JIT compilation should be avoided.
473          */
474         if (IS_ON_SIGALTSTACK (jit_tls)) {
475                 /* 
476                  * FIXME: disabling/enabling GC while already on a signal stack might
477                  * not be safe either.
478                  */
479                 /* Have to reenable it later */
480                 gc_disabled = TRUE;
481                 mono_gc_disable ();
482         }
483
484         g_assert (ctx != NULL);
485         if (!obj) {
486                 MonoException *ex = mono_get_exception_null_reference ();
487                 ex->message = mono_string_new (domain, "Object reference not set to an instance of an object");
488                 obj = (MonoObject *)ex;
489         } 
490
491         if (mono_object_isinst (obj, mono_defaults.exception_class)) {
492                 mono_ex = (MonoException*)obj;
493                 mono_ex->stack_trace = NULL;
494         } else {
495                 mono_ex = NULL;
496         }
497
498         //printf ("HANDLING EXCEPTION: %s\n", ((MonoObject*)obj)->vtable->klass->name);
499         
500         if (obj == domain->stack_overflow_ex)
501                 stack_overflow = TRUE;
502
503         if (!call_filter)
504                 call_filter = arch_get_call_filter ();
505
506         if (!restore_context)
507                 restore_context = arch_get_restore_context ();
508
509         g_assert (jit_tls->end_of_stack);
510         g_assert (jit_tls->abort_func);
511
512         if (!test_only) {
513                 MonoContext ctx_cp = *ctx;
514                 if (mono_jit_trace_calls != NULL)
515                         g_print ("EXCEPTION handling: %s\n", mono_object_class (obj)->name);
516                 if (!mono_sparc_handle_exception (&ctx_cp, obj, TRUE)) {
517                         if (mono_break_on_exc)
518                                 G_BREAKPOINT ();
519                         mono_unhandled_exception (obj);
520                 }
521         }
522
523         initial_ctx = *ctx;
524         memset (&rji, 0, sizeof (rji));
525
526         while (1) {
527                 MonoContext new_ctx;
528                 char *trace = NULL;
529                 gboolean need_trace = FALSE;
530                 guint32 free_stack;
531
532                 if (test_only && (frame_count < 1000))
533                         need_trace = TRUE;
534
535                 ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &rji, ctx, &new_ctx, 
536                                               need_trace ? &trace : NULL, &lmf, NULL, NULL);
537                 if (!ji) {
538                         g_warning ("Exception inside function without unwind info");
539                         g_assert_not_reached ();
540                 }
541
542                 //printf ("JI: %p IP: %p SP: %p.\n", ji, (gpointer)new_ctx.ip, new_ctx.sp);
543
544                 if (ji != (gpointer)-1) {
545                         frame_count ++;
546                         //printf ("M: %s %p %p %d.\n", mono_method_full_name (ji->method, TRUE), jit_tls->end_of_stack, ctx->ebp, count);
547
548                         if (test_only && ji->method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE && mono_ex) {
549                                 char *tmp, *strace;
550
551                                 /* Avoid giant stack traces */
552                                 if (frame_count < 1000) {
553                                         trace_ips = g_list_append (trace_ips, MONO_CONTEXT_GET_IP (ctx));
554
555                                         if (!mono_ex->stack_trace)
556                                                 strace = g_strdup ("");
557                                         else
558                                                 strace = mono_string_to_utf8 (mono_ex->stack_trace);
559                         
560                                         tmp = g_strdup_printf ("%s%s\n", strace, trace);
561                                         g_free (strace);
562                                         
563                                         mono_ex->stack_trace = mono_string_new (domain, tmp);
564
565                                         g_free (tmp);
566                                 }
567                         }
568
569 /*
570                         if (stack_overflow)
571                                 free_stack = (guint8*)(MONO_CONTEXT_GET_BP (ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
572                         else
573                                 free_stack = 0xffffff;
574 */
575                         free_stack = 0xffffff;
576
577                         /* 
578                          * During stack overflow, wait till the unwinding frees some stack
579                          * space before running handlers/finalizers.
580                          */
581                         if ((free_stack > (64 * 1024)) && ji->num_clauses) {
582                                 int i;
583                                 
584                                 g_assert (ji->clauses);
585                         
586                                 for (i = 0; i < ji->num_clauses; i++) {
587                                         MonoJitExceptionInfo *ei = &ji->clauses [i];
588
589                                         if (ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
590                                             MONO_CONTEXT_GET_IP (ctx) <= ei->try_end) { 
591                                                 /* catch block */
592
593                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE) || (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)) {
594                                                         /* store the exception object int cfg->excvar */
595                                                         g_assert (ji->exvar_offset);
596                                                         *((gpointer *)((char *)MONO_CONTEXT_GET_BP (ctx) + ji->exvar_offset)) = obj;
597                                                 }
598
599                                                 if ((ei->flags == MONO_EXCEPTION_CLAUSE_NONE && 
600                                                      mono_object_isinst (obj, mono_class_get (ji->method->klass->image, ei->data.token))) ||
601                                                     ((ei->flags == MONO_EXCEPTION_CLAUSE_FILTER &&
602                                                       call_filter (ctx, ei->data.filter)))) {
603                                                         if (test_only) {
604                                                                 if (mono_ex)
605                                                                         mono_ex->trace_ips = glist_to_array (trace_ips);
606                                                                 g_list_free (trace_ips);
607                                                                 g_free (trace);
608
609                                                                 if (gc_disabled)
610                                                                         mono_gc_enable ();
611                                                                 return TRUE;
612                                                         }
613                                                         if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
614                                                                 g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
615                                                         MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
616                                                         jit_tls->lmf = lmf;
617                                                         g_free (trace);
618
619                                                         if (gc_disabled)
620                                                                 mono_gc_enable ();
621                                                         return 0;
622                                                 }
623                                                 if (!test_only && ei->try_start <= MONO_CONTEXT_GET_IP (ctx) && 
624                                                     MONO_CONTEXT_GET_IP (ctx) < ei->try_end &&
625                                                     (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
626                                                         if (mono_jit_trace_calls != NULL && mono_trace_eval (ji->method))
627                                                                 g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (ji->method, TRUE));
628                                                         call_filter (ctx, ei->handler_start);
629                                                 }
630                                                 
631                                         }
632                                 }
633                         }
634                 }
635
636                 g_free (trace);
637                         
638                 *ctx = new_ctx;
639
640                 if ((ji == (gpointer)-1) || MONO_CONTEXT_GET_BP (ctx) >= jit_tls->end_of_stack) {
641                         if (gc_disabled)
642                                 mono_gc_enable ();
643
644                         if (!test_only) {
645                                 jit_tls->lmf = lmf;
646
647                                 if (IS_ON_SIGALTSTACK (jit_tls)) {
648                                         /* Switch back to normal stack */
649                                         if (stack_overflow)
650                                                 /* Free up some stack space */
651                                                 initial_ctx.sp += (64 * 1024);
652                                         initial_ctx.ip = (unsigned int)jit_tls->abort_func;
653                                         restore_context (&initial_ctx);
654                                 }
655                                 else
656                                         jit_tls->abort_func (obj);
657                                 g_assert_not_reached ();
658                         } else {
659                                 if (mono_ex)
660                                         mono_ex->trace_ips = glist_to_array (trace_ips);
661                                 g_list_free (trace_ips);
662                                 return FALSE;
663                         }
664                 }
665         }
666
667         g_assert_not_reached ();
668 }
669
670 gboolean
671 mono_arch_handle_exception (ucontext_t *ctx, gpointer obj, gboolean test_only)
672 {
673         MonoContext mctx;
674
675         /*
676          * Access to the machine state using the ucontext_t parameter is somewhat
677          * under documented under solaris. The code below seems to work under
678          * Solaris 9.
679          */
680         g_assert (!ctx->uc_mcontext.gwins);
681
682         mctx.ip = ctx->uc_mcontext.gregs [REG_PC];
683         mctx.sp = ctx->uc_mcontext.gregs [REG_SP];
684         mctx.fp = mctx.sp [sparc_fp - 16];
685
686         mono_sparc_handle_exception (&mctx, obj, test_only);
687         
688         /* We can't use restore_context to return from a signal handler */
689         ctx->uc_mcontext.gregs [REG_PC] = mctx.ip;
690         ctx->uc_mcontext.gregs [REG_nPC] = mctx.ip + 4;
691         ctx->uc_mcontext.gregs [REG_SP] = mctx.sp;
692         mctx.sp [sparc_fp - 16] = mctx.fp;
693
694         return TRUE;
695 }