2009-09-22 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / exceptions-hppa.c
1 /*
2  * exceptions-hppa.c: exception support for HPPA
3  *
4  * Copyright (c) 2007 Randolph Chung
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  */
25
26 #include <config.h>
27 #include <glib.h>
28 #include <signal.h>
29 #include <string.h>
30 #include <ucontext.h>
31
32 #include <mono/arch/hppa/hppa-codegen.h>
33 #include <mono/metadata/appdomain.h>
34 #include <mono/metadata/tabledefs.h>
35 #include <mono/metadata/threads.h>
36 #include <mono/metadata/debug-helpers.h>
37 #include <mono/metadata/exception.h>
38 #include <mono/metadata/mono-debug.h>
39
40 #include "mini.h"
41 #include "mini-hppa.h"
42
43 #define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
44
45 #define restore_regs_from_context(ctx_reg,ip_reg) do {                  \
46                 int reg, ofs;                                           \
47                 hppa_ldw (code, G_STRUCT_OFFSET (MonoContext, pc), \
48                         ctx_reg, ip_reg);                               \
49                 ofs = G_STRUCT_OFFSET (MonoContext, regs);              \
50                 for (reg = 0; reg < 32; ++reg) {                        \
51                         if (HPPA_IS_SAVED_GREG (reg)) {                 \
52                                 hppa_ldw (code, ofs, ctx_reg, reg);     \
53                                 ofs += 4;                               \
54                         }                                               \
55                 }                                                       \
56                 hppa_set (code, G_STRUCT_OFFSET (MonoContext, fregs), hppa_r1); \
57                 for (reg = 4; reg < 32; ++reg) {                        \
58                         if (HPPA_IS_SAVED_FREG (reg)) {                 \
59                                 hppa_flddx (code, hppa_r1, ctx_reg, reg); \
60                                 hppa_ldo (code, sizeof(double), hppa_r1, hppa_r1); \
61                         }                                               \
62                 }                                                       \
63         } while (0)
64
65
66 /* HPPA bit ops */
67 static inline int
68 hppa_low_sign_extend (unsigned val, unsigned bits)
69 {
70         return (int) ((val & 0x1 ? (-1 << (bits - 1)) : 0) | val >> 1);
71 }
72
73 static inline int
74 hppa_sign_extend (unsigned val, unsigned bits)
75 {
76         return (int) (val >> (bits - 1) ? (-1 << bits) | val : val);
77 }
78
79 static inline int
80 hppa_get_field (unsigned word, int from, int to)
81 {
82         return ((word) >> (31 - (to)) & ((1 << ((to) - (from) + 1)) - 1));
83 }
84
85 static inline int
86 hppa_extract_14 (unsigned word)
87 {
88         return hppa_low_sign_extend (word & 0x3fff, 14);
89 }
90
91 static inline int
92 hppa_extract_21 (unsigned word)
93 {
94         int val;
95
96         word &= 0x1fffff;
97         word <<= 11;
98         val = hppa_get_field (word, 20, 20);
99         val <<= 11;
100         val |= hppa_get_field (word, 9, 19);
101         val <<= 2;
102         val |= hppa_get_field (word, 5, 6);
103         val <<= 5;
104         val |= hppa_get_field (word, 0, 4);
105         val <<= 2;
106         val |= hppa_get_field (word, 7, 8);
107         return hppa_sign_extend (val, 21) << 11;
108 }
109
110 static inline int
111 hppa_is_branch(unsigned int insn)
112 {
113         switch (insn >> 26)
114         {
115                 case 0x20:
116                 case 0x21:
117                 case 0x22:
118                 case 0x23:
119                 case 0x27:
120                 case 0x28:
121                 case 0x29:
122                 case 0x2a:
123                 case 0x2b:
124                 case 0x2f:
125                 case 0x30:
126                 case 0x31:
127                 case 0x32:
128                 case 0x33:
129                 case 0x38:
130                 case 0x39:
131                 case 0x3a:
132                 case 0x3b:
133                         return 1;
134
135                 default:
136                         return 0;
137         }
138 }
139
140 /*
141  * arch_get_restore_context:
142  *
143  * Returns a pointer to a method which restores a previously saved sigcontext.
144  * called as restore_context(MonoContext *ctx)
145  */
146 gpointer
147 mono_arch_get_restore_context (void)
148 {
149         guint8 *code;
150         static guint8 start [384];
151         static int inited = 0;
152
153         if (inited)
154                 return start;
155         inited = 1;
156
157         code = start;
158         restore_regs_from_context (hppa_r26, hppa_r20);
159         /* restore also the stack pointer */
160         hppa_ldw (code, G_STRUCT_OFFSET (MonoContext, sp), hppa_r26, hppa_r30);
161         /* jump to the saved IP */
162         hppa_bv (code, hppa_r0, hppa_r20);
163         hppa_nop (code);
164
165         /* not reached */
166         *(guint32 *)code = 0xdeadbeef;
167
168         g_assert ((code - start) < sizeof(start));
169         mono_arch_flush_icache (start, code - start);
170         return start;
171 }
172
173 /*
174  * arch_get_call_filter:
175  *
176  * Returns a pointer to a method which calls an exception filter. We
177  * also use this function to call finally handlers (we pass NULL as 
178  * @exc object in this case).
179  */
180 gpointer
181 mono_arch_get_call_filter (void)
182 {
183         static guint8 start [1024];
184         static int inited = 0;
185         guint8 *code;
186         int pos, i;
187
188         if (inited)
189                 return start;
190
191         inited = 1;
192         /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
193         code = start;
194
195         /* Save the return pointer in its regular location */
196         hppa_stw (code, hppa_r2, -20, hppa_r30);
197
198         /* Save all the registers on the stack */
199         pos = 0;
200         for (i = 0; i < 32; i++) {
201                 if (HPPA_IS_SAVED_GREG (i)) {
202                         hppa_stw (code, i, pos, hppa_sp);
203                         pos += sizeof(gulong);
204                 }
205         }
206         pos = ALIGN_TO (pos, sizeof(double));
207         hppa_set (code, pos, hppa_r1);
208         for (i = 0; i < 32; i++) {
209                 if (HPPA_IS_SAVED_FREG (i)) {
210                         hppa_fstdx (code, i, hppa_r1, hppa_sp);
211                         hppa_ldo (code, sizeof(double), hppa_r1, hppa_r1);
212                         pos += sizeof(double);
213                 }
214         }
215
216         pos += 64; /* Leave space for the linkage area */
217         pos = ALIGN_TO (pos, MONO_ARCH_FRAME_ALIGNMENT);
218
219         hppa_ldo (code, pos, hppa_sp, hppa_sp);
220
221         /* restore all the regs from ctx (in r26), but not the stack pointer */
222         restore_regs_from_context (hppa_r26, hppa_r20);
223
224         /* call handler at the saved IP (r25) */
225         hppa_ble (code, 0, hppa_r25);
226         hppa_copy (code, hppa_r31, hppa_r2);
227
228         /* epilog */
229         hppa_ldo (code, -pos, hppa_sp, hppa_sp);
230
231         /* Restore registers */
232         pos = 0;
233         for (i = 0; i < 32; i++) {
234                 if (HPPA_IS_SAVED_GREG (i)) {
235                         hppa_ldw (code, pos, hppa_sp, i);
236                         pos += sizeof(gulong);
237                 }
238         }
239         pos = ALIGN_TO (pos, sizeof(double));
240         hppa_set (code, pos, hppa_r1);
241         for (i = 0; i < 32; i++) {
242                 if (HPPA_IS_SAVED_FREG (i)) {
243                         hppa_flddx (code, hppa_r1, hppa_sp, i);
244                         hppa_ldo (code, sizeof(double), hppa_r1, hppa_r1);
245                         pos += sizeof(double);
246                 }
247         }
248
249         hppa_ldw (code, -20, hppa_sp, hppa_r2);
250         hppa_bv (code, hppa_r0, hppa_r2);
251         hppa_nop (code);
252
253         g_assert ((code - start) < sizeof(start));
254         mono_arch_flush_icache (start, code - start);
255         return start;
256 }
257
258 static void
259 throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp, gulong *int_regs, gdouble *fp_regs, gboolean rethrow)
260 {
261         static void (*restore_context) (MonoContext *);
262         MonoContext ctx;
263
264         if (!restore_context)
265                 restore_context = mono_arch_get_restore_context ();
266
267         /* adjust eip so that it point into the call instruction */
268         eip &= ~3;
269         eip -= 8;
270
271         MONO_CONTEXT_SET_BP (&ctx, esp);
272         MONO_CONTEXT_SET_IP (&ctx, eip);
273         memcpy (&ctx.regs, int_regs, sizeof (gulong) * MONO_SAVED_GREGS);
274         memcpy (&ctx.fregs, fp_regs, sizeof (double) * MONO_SAVED_FREGS);
275
276         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
277                 MonoException *mono_ex = (MonoException*)exc;
278                 if (!rethrow)
279                         mono_ex->stack_trace = NULL;
280         }
281         mono_handle_exception (&ctx, exc, (gpointer)(eip + 8), FALSE);
282
283         restore_context (&ctx);
284
285         g_assert_not_reached ();
286 }
287
288 /**
289  * arch_get_throw_exception_generic:
290  *
291  * Returns a function pointer which can be used to raise 
292  * exceptions. The returned function has the following 
293  * signature: void (*func) (MonoException *exc); or
294  * void (*func) (char *exc_name);
295  *
296  */
297 static gpointer 
298 mono_arch_get_throw_exception_generic (guint8 *start, int size, int by_name, gboolean rethrow)
299 {
300         guint8 *code;
301         int pos, frpos, i;
302
303         code = start;
304
305         /* We are called with r26 = exception */
306         /* Stash the call site IP in the "return pointer" slot */
307         hppa_stw (code, hppa_r2, -20, hppa_sp);
308
309         /* Non-standard prologue - we don't want to clobber r3 */
310         hppa_copy (code, hppa_sp, hppa_r1);
311         hppa_ldo (code, 512, hppa_sp, hppa_sp);
312
313         /* Save all the registers on the stack */
314         pos = 0;
315         for (i = 0; i < 32; i++) {
316                 if (HPPA_IS_SAVED_GREG (i)) {
317                         hppa_stw (code, i, pos, hppa_r1);
318                         pos += sizeof(gulong);
319                 }
320         }
321         pos = ALIGN_TO (pos, sizeof(double));
322         frpos = pos;
323         hppa_set (code, pos, hppa_r20);
324         for (i = 0; i < 32; i++) {
325                 if (HPPA_IS_SAVED_FREG (i)) {
326                         hppa_fstdx (code, i, hppa_r20, hppa_r1);
327                         hppa_ldo (code, sizeof(double), hppa_r20, hppa_r20);
328                         pos += sizeof(double);
329                 }
330         }
331
332         /* Now that we have saved r4, we copy the stack pointer to it for
333          * use below - we want a callee save register in case we do the
334          * function call below
335          */
336         hppa_copy (code, hppa_r1, hppa_r4);
337
338         if (by_name) {
339                 /* mono_exception_from_name (MonoImage *image, 
340                  *                           const char *name_space,
341                  *                           const char *name)
342                  */
343                 void *func = __canonicalize_funcptr_for_compare (mono_exception_from_name);
344                 hppa_copy (code, hppa_r26, hppa_r24);
345                 hppa_set (code, mono_defaults.corlib, hppa_r26);
346                 hppa_set (code, "System", hppa_r25);
347                 hppa_ldil (code, hppa_lsel (func), hppa_r1);
348                 hppa_ble (code, hppa_rsel (func), hppa_r1);
349                 hppa_copy (code, hppa_r31, hppa_r2);
350                 hppa_copy (code, hppa_r28, hppa_r26);
351         }
352
353         /* call throw_exception (exc, ip, sp, int_regs, fp_regs, rethrow) */
354         /* exc is already in place in r26 */
355
356         hppa_ldw (code, -20, hppa_r4, hppa_r25); /* ip */
357         hppa_copy (code, hppa_r4, hppa_r24); /* sp */
358         hppa_ldo (code, 0, hppa_r4, hppa_r23);
359         hppa_ldo (code, frpos, hppa_r4, hppa_r22);
360         hppa_stw (code, hppa_r22, -52, hppa_sp);
361         hppa_ldo (code, rethrow, hppa_r0, hppa_r22);
362         hppa_stw (code, hppa_r22, -56, hppa_sp);
363
364         hppa_set (code, throw_exception, hppa_r1);
365         hppa_depi (code, 0, 31, 2, hppa_r1);
366         hppa_ldw (code, 0, hppa_r1, hppa_r1);
367         hppa_bv (code, hppa_r0, hppa_r1);
368         hppa_nop (code);
369
370         /* not reached */
371         *(guint32 *)code = 0x88c0ffee;
372
373         g_assert ((code - start) < size);
374         mono_arch_flush_icache (start, code - start);
375         return start;
376 }
377
378 /**
379  * mono_arch_get_rethrow_exception:
380  *
381  * Returns a function pointer which can be used to rethrow 
382  * exceptions. The returned function has the following 
383  * signature: void (*func) (MonoException *exc); 
384  *
385  */
386 gpointer
387 mono_arch_get_rethrow_exception (void)
388 {
389         static guint8 start [450];
390         static int inited = 0;
391
392         if (inited)
393                 return start;
394         mono_arch_get_throw_exception_generic (start, sizeof (start), FALSE, TRUE);
395         inited = 1;
396         return start;
397 }
398 /**
399  * arch_get_throw_exception:
400  *
401  * Returns a function pointer which can be used to raise 
402  * exceptions. The returned function has the following 
403  * signature: void (*func) (MonoException *exc); 
404  * For example to raise an arithmetic exception you can use:
405  *
406  * x86_push_imm (code, mono_get_exception_arithmetic ()); 
407  * x86_call_code (code, arch_get_throw_exception ()); 
408  *
409  */
410 gpointer 
411 mono_arch_get_throw_exception (void)
412 {
413         static guint8 start [450];
414         static int inited = 0;
415
416         if (inited)
417                 return start;
418         mono_arch_get_throw_exception_generic (start, sizeof (start), FALSE, FALSE);
419         inited = 1;
420         return start;
421 }
422
423 /**
424  * arch_get_throw_exception_by_name:
425  *
426  * Returns a function pointer which can be used to raise 
427  * corlib exceptions. The returned function has the following 
428  * signature: void (*func) (char *exc_name); 
429  * For example to raise an arithmetic exception you can use:
430  *
431  * x86_push_imm (code, "ArithmeticException"); 
432  * x86_call_code (code, arch_get_throw_exception_by_name ()); 
433  *
434  */
435 gpointer 
436 mono_arch_get_throw_exception_by_name (void)
437 {
438         static guint8 start [450];
439         static int inited = 0;
440
441         if (inited)
442                 return start;
443         mono_arch_get_throw_exception_generic (start, sizeof (start), TRUE, FALSE);
444         inited = 1;
445         return start;
446 }       
447
448 static int
449 hppa_get_size_of_frame (MonoJitInfo *ji, int *stored_fp)
450 {
451         guint32 *insn = (guint32 *)((unsigned long)ji->code_start & ~3);
452         guint32 *end = (guint32 *)((unsigned long)ji->code_start + ji->code_size);
453         int saw_branch = 0;
454         int stack_size = 0;
455
456         /* Look for the instruction that adjusts the stack pointer */
457         while (insn < end) {
458                 /* ldo X(sp), sp */
459                 if ((insn[0] & 0xffffc000) == 0x37de0000) {
460                         stack_size += hppa_extract_14 (insn [0]);
461                 }
462                 /* stwm X,D(sp) */
463                 else if ((insn[0] & 0xffe00000) == 0x6fc00000) {
464                         stack_size += hppa_extract_14 (insn [0]);
465                         if (stored_fp)
466                                 *stored_fp = 1;
467                 }
468                 /* addil/ldo */
469                 else if (((insn[0] & 0xffe00000) == 0x28200000) &&
470                          ((insn[1] & 0xffff0000) == 0x343e0000)) {
471                          stack_size += hppa_extract_21 (insn [0]);
472                          stack_size += hppa_extract_14 (insn [1]);
473                          insn++;
474                 }
475
476                 insn++;
477                 if (saw_branch)
478                         break;
479                 saw_branch = hppa_is_branch (insn[0]);
480         }
481
482         if (stack_size == 0) {
483                 g_print ("No stack frame found for function at %p\n", ji->code_start);
484         }
485
486         return stack_size;
487 }
488
489 static void
490 hppa_analyze_frame (MonoJitInfo *ji, MonoContext *ctx, MonoContext *new_ctx)
491 {
492         unsigned char *sp;
493         int stack_size;
494         int stored_fp = 0;
495
496         stack_size = hppa_get_size_of_frame (ji, &stored_fp);
497
498         sp = (unsigned char *)MONO_CONTEXT_GET_BP (ctx) - stack_size;
499         MONO_CONTEXT_SET_BP (new_ctx, sp);
500         MONO_CONTEXT_SET_IP (new_ctx, *(unsigned int *)(sp - 20));
501
502         if (ji->method->save_lmf) {
503                 memcpy (&new_ctx->regs, (char *)sp + HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, regs), sizeof (gulong) * MONO_SAVED_GREGS);
504                 memcpy (&new_ctx->fregs, (char *)sp + HPPA_STACK_LMF_OFFSET + G_STRUCT_OFFSET (MonoLMF, fregs), sizeof (double) * MONO_SAVED_FREGS);
505         }
506         else if (ji->used_regs) {
507                 char *pos = (char *)sp + HPPA_STACK_LMF_OFFSET;
508                 gulong val;
509                 int i, j = 0;
510
511                 for (i = 0; i <= 32; i++) {
512                         if ((1 << i) & ji->used_regs) {
513                                 val = *(gulong *)pos;
514                                 pos += sizeof (gulong);
515                                 new_ctx->regs [j] = val;
516                         }
517                         if (HPPA_IS_SAVED_GREG (i))
518                                 j++;
519                 }
520         }
521         if (stored_fp) {
522                 gulong val;
523                 val = *(gulong *)sp;
524                 new_ctx->regs [0] = val;
525         }
526 }
527
528 /* mono_arch_find_jit_info:
529  *
530  * This function is used to gather information from @ctx. It return the 
531  * MonoJitInfo of the corresponding function, unwinds one stack frame and
532  * stores the resulting context into @new_ctx. It also stores a string 
533  * describing the stack location into @trace (if not NULL), and modifies
534  * the @lmf if necessary. @native_offset return the IP offset from the 
535  * start of the function or -1 if that info is not available.
536  */
537 MonoJitInfo *
538 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji,
539                          MonoContext *ctx, MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
540 {
541         MonoJitInfo *ji;
542         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
543
544         /* Avoid costly table lookup during stack overflow */
545         if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
546                 ji = prev_ji;
547         else
548                 ji = mini_jit_info_table_find (domain, ip);
549
550         if (managed)
551                 *managed = FALSE;
552
553         if (ji != NULL) {
554                 gint32 address;
555
556                 *new_ctx = *ctx;
557
558                 address = (char *)ip - (char *)ji->code_start;
559
560                 if (managed)
561                         if (!ji->method->wrapper_type)
562                                 *managed = TRUE;
563
564                 if (*lmf && (*lmf)->ebp != 0xffffffff && (MONO_CONTEXT_GET_BP (ctx) <= (gpointer)(*lmf)->ebp)) {
565                         /* remove any unused lmf */
566                         *lmf = (*lmf)->previous_lmf;
567                 }
568
569                 hppa_analyze_frame (ji, ctx, new_ctx);
570                 //printf("Managed frame: rewound (ip,sp)=(%x [%s],%x) to (%x,%x)\n", ctx->pc, mono_method_full_name (ji->method, FALSE), ctx->sp, new_ctx->pc, new_ctx->sp);
571
572                 return ji;
573         } else if (*lmf) {
574                 
575                 *new_ctx = *ctx;
576
577                 if (!(*lmf)->method)
578                         return (gpointer)-1;
579
580                 if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
581                 } else {
582                         memset (res, 0, MONO_SIZEOF_JIT_INFO);
583                         res->method = (*lmf)->method;
584                 }
585
586                 MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp);
587                 MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip);
588                 memcpy (&new_ctx->regs, (*lmf)->regs, sizeof (gulong) * MONO_SAVED_GREGS);
589                 memcpy (&new_ctx->fregs, (*lmf)->regs, sizeof (double) * MONO_SAVED_FREGS);
590                 *lmf = (*lmf)->previous_lmf;
591                 //printf("Unmanaged frame: rewound to (ip,sp)=(%x [%s],%x)\n", new_ctx->pc, mono_method_full_name (ji ? ji->method : res->method, FALSE), new_ctx->sp);
592
593                 return ji ? ji : res;
594         }
595
596         return NULL;
597 }
598
599 gboolean
600 mono_arch_has_unwind_info (gconstpointer addr)
601 {
602         return FALSE;
603 }
604
605 /*
606  * This is the function called from the signal handler
607  */
608 gboolean
609 mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
610 {
611         struct ucontext *uc = sigctx;
612         MonoContext mctx;
613         gboolean result;
614         int i, grs, frs;
615
616         mctx.pc = uc->uc_mcontext.sc_iaoq [0];
617         mctx.sp = uc->uc_mcontext.sc_gr [30];
618
619         grs = 0; frs = 0;
620         for (i = 0; i < 32; i++) {
621                 if (HPPA_IS_SAVED_GREG (i))
622                         mctx.regs[grs++] = uc->uc_mcontext.sc_gr [i];
623                 if (HPPA_IS_SAVED_FREG (i))
624                         mctx.fregs[frs++] = uc->uc_mcontext.sc_fr [i];
625         }
626         g_assert (grs == MONO_SAVED_GREGS && frs == MONO_SAVED_FREGS);
627
628         result = mono_handle_exception (&mctx, obj, (gpointer)mctx.pc, test_only);
629
630         /* restore the context so that returning from the signal handler will invoke
631          * the catch clause 
632          */
633         uc->uc_mcontext.sc_iaoq [0] = mctx.pc;
634         uc->uc_mcontext.sc_iaoq [1] = mctx.pc + 4;
635         uc->uc_mcontext.sc_gr [30] = mctx.sp;
636
637         grs = 0; frs = 0;
638         for (i = 0; i < 32; i++) {
639                 if (HPPA_IS_SAVED_GREG (i))
640                         uc->uc_mcontext.sc_gr [i] = mctx.regs [grs++];
641                 if (HPPA_IS_SAVED_FREG (i))
642                         uc->uc_mcontext.sc_fr [i] = mctx.fregs [frs++];
643         }
644
645         return result;
646 }
647
648 gpointer
649 mono_arch_ip_from_context (void *sigctx)
650 {
651         struct ucontext *uc = sigctx;
652         return (gpointer)uc->uc_mcontext.sc_iaoq [0];
653 }