1a85d0a2469505f948ad6ba5b3a2cec12a65a9e7
[mono.git] / mono / mini / exceptions-s390.c
1 /*------------------------------------------------------------------*/
2 /*                                                                  */
3 /* Name        - exceptions-s390.c                                  */
4 /*                                                                  */
5 /* Function    - Exception support for S/390.                       */
6 /*                                                                  */
7 /* Name        - Neale Ferguson (Neale.Ferguson@SoftwareAG-usa.com) */
8 /*                                                                  */
9 /* Date        - January, 2004                                      */
10 /*                                                                  */
11 /* Derivation  - From exceptions-x86 & exceptions-ppc               */
12 /*               Paolo Molaro (lupus@ximian.com)                    */
13 /*               Dietmar Maurer (dietmar@ximian.com)                */
14 /*                                                                  */
15 /* Copyright   - 2001 Ximian, Inc.                                  */
16 /*                                                                  */
17 /*------------------------------------------------------------------*/
18
19 /*------------------------------------------------------------------*/
20 /*                 D e f i n e s                                    */
21 /*------------------------------------------------------------------*/
22
23 #define S390_CALLFILTER_INTREGS         S390_MINIMAL_STACK_SIZE
24 #define S390_CALLFILTER_FLTREGS         S390_CALLFILTER_INTREGS+(16*sizeof(gulong))
25 #define S390_CALLFILTER_ACCREGS         S390_CALLFILTER_FLTREGS+(16*sizeof(gdouble))
26 #define S390_CALLFILTER_SIZE            (S390_CALLFILTER_ACCREGS+(16*sizeof(gulong)))
27
28 #define S390_THROWSTACK_ACCPRM          S390_MINIMAL_STACK_SIZE
29 #define S390_THROWSTACK_FPCPRM          S390_THROWSTACK_ACCPRM+sizeof(gpointer)
30 #define S390_THROWSTACK_RETHROW         S390_THROWSTACK_FPCPRM+sizeof(gulong)
31 #define S390_THROWSTACK_INTREGS         S390_THROWSTACK_RETHROW+sizeof(gboolean)
32 #define S390_THROWSTACK_FLTREGS         S390_THROWSTACK_INTREGS+(16*sizeof(gulong))
33 #define S390_THROWSTACK_ACCREGS         S390_THROWSTACK_FLTREGS+(16*sizeof(gdouble))
34 #define S390_THROWSTACK_SIZE            (S390_THROWSTACK_ACCREGS+(16*sizeof(gulong)))
35
36 #define SZ_THROW        384
37
38 /*========================= End of Defines =========================*/
39
40 /*------------------------------------------------------------------*/
41 /*                 I n c l u d e s                                  */
42 /*------------------------------------------------------------------*/
43
44 #include <config.h>
45 #include <glib.h>
46 #include <signal.h>
47 #include <string.h>
48 #include <ucontext.h>
49
50 #include <mono/arch/s390/s390-codegen.h>
51 #include <mono/metadata/appdomain.h>
52 #include <mono/metadata/tabledefs.h>
53 #include <mono/metadata/threads.h>
54 #include <mono/metadata/debug-helpers.h>
55 #include <mono/metadata/exception.h>
56 #include <mono/metadata/mono-debug.h>
57
58 #include "mini.h"
59 #include "mini-s390.h"
60
61 /*========================= End of Includes ========================*/
62
63 /*------------------------------------------------------------------*/
64 /*                   P r o t o t y p e s                            */
65 /*------------------------------------------------------------------*/
66
67 gboolean mono_arch_handle_exception (void     *ctx,
68                                      gpointer obj, 
69                                      gboolean test_only);
70
71 /*========================= End of Prototypes ======================*/
72
73 /*------------------------------------------------------------------*/
74 /*                 G l o b a l   V a r i a b l e s                  */
75 /*------------------------------------------------------------------*/
76
77 /*====================== End of Global Variables ===================*/
78
79 /*------------------------------------------------------------------*/
80 /*                                                                  */
81 /* Name         - mono_arch_has_unwind_info                         */
82 /*                                                                  */
83 /* Function     - Tests if a function has a DWARF exception table   */
84 /*                that is able to restore all caller saved registers*/
85 /*                                                                  */
86 /*------------------------------------------------------------------*/
87
88 gboolean
89 mono_arch_has_unwind_info (gconstpointer addr)
90 {
91         return FALSE;
92 }
93
94 /*========================= End of Function ========================*/
95
96 /*------------------------------------------------------------------*/
97 /*                                                                  */
98 /* Name         - mono_arch_get_call_filter                         */
99 /*                                                                  */
100 /* Function     - Return a pointer to a method which calls an       */
101 /*                exception filter. We also use this function to    */
102 /*                call finally handlers (we pass NULL as @exc       */
103 /*                object in this case).                             */
104 /*                                                                  */
105 /*------------------------------------------------------------------*/
106
107 gpointer
108 mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
109 {
110         static guint8 *start;
111         static int inited = 0;
112         guint8 *code;
113         int alloc_size, pos, i;
114
115         g_assert (!aot);
116         if (info)
117                 *info = NULL;
118
119         if (inited)
120                 return start;
121
122         inited = 1;
123         /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
124         code = start = mono_global_codeman_reserve (512);
125
126         s390_stm (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
127         s390_lr  (code, s390_r14, STK_BASE);
128         alloc_size = S390_ALIGN(S390_CALLFILTER_SIZE, S390_STACK_ALIGNMENT);
129         s390_ahi (code, STK_BASE, -alloc_size);
130         s390_st  (code, s390_r14, 0, STK_BASE, 0);
131
132         /*------------------------------------------------------*/
133         /* save general registers on stack                      */
134         /*------------------------------------------------------*/
135         s390_stm (code, s390_r0, s390_r13, STK_BASE, S390_CALLFILTER_INTREGS);
136
137         /*------------------------------------------------------*/
138         /* save floating point registers on stack               */
139         /*------------------------------------------------------*/
140 //      pos = S390_CALLFILTER_FLTREGS;
141 //      for (i = 0; i < 16; ++i) {
142 //              s390_std (code, i, 0, STK_BASE, pos);
143 //              pos += sizeof (gdouble);
144 //      }
145
146         /*------------------------------------------------------*/
147         /* save access registers on stack                       */
148         /*------------------------------------------------------*/
149 //      s390_stam (code, s390_a0, s390_a15, STK_BASE, S390_CALLFILTER_ACCREGS);
150
151         /*------------------------------------------------------*/
152         /* Get A(Context)                                       */
153         /*------------------------------------------------------*/
154         s390_lr   (code, s390_r13, s390_r2);
155
156         /*------------------------------------------------------*/
157         /* Get A(Handler Entry Point)                           */
158         /*------------------------------------------------------*/
159         s390_lr   (code, s390_r0, s390_r3);
160
161         /*------------------------------------------------------*/
162         /* Set parameter register with Exception                */
163         /*------------------------------------------------------*/
164         s390_lr   (code, s390_r2, s390_r4);
165
166         /*------------------------------------------------------*/
167         /* Load all registers with values from the context      */
168         /*------------------------------------------------------*/
169         s390_lm   (code, s390_r3, s390_r12, s390_r13, 
170                    G_STRUCT_OFFSET(MonoContext, uc_mcontext.gregs[3]));
171         pos = G_STRUCT_OFFSET(MonoContext, uc_mcontext.fpregs.fprs[0]);
172         for (i = 0; i < 16; ++i) {
173                 s390_ld  (code, i, 0, s390_r13, pos);
174                 pos += sizeof(gdouble);
175         }
176         
177         /*------------------------------------------------------*/
178         /* Point at the copied stack frame and call the filter  */
179         /*------------------------------------------------------*/
180         s390_lr   (code, s390_r1, s390_r0);
181         s390_basr (code, s390_r14, s390_r1);
182
183         /*------------------------------------------------------*/
184         /* Save return value                                    */
185         /*------------------------------------------------------*/
186         s390_lr   (code, s390_r14, s390_r2);
187
188         /*------------------------------------------------------*/
189         /* Restore all the regs from the stack                  */
190         /*------------------------------------------------------*/
191         s390_lm (code, s390_r0, s390_r13, STK_BASE, S390_CALLFILTER_INTREGS);
192 //      pos = S390_CALLFILTER_FLTREGS;
193 //      for (i = 0; i < 16; ++i) {
194 //              s390_ld (code, i, 0, STK_BASE, pos);
195 //              pos += sizeof (gdouble);
196 //      }
197
198         s390_lr   (code, s390_r2, s390_r14);
199 //      s390_lam  (code, s390_a0, s390_a15, STK_BASE, S390_CALLFILTER_ACCREGS);
200         s390_ahi  (code, s390_r15, alloc_size);
201         s390_lm   (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
202         s390_br   (code, s390_r14);
203
204         g_assert ((code - start) < SZ_THROW); 
205         return start;
206 }
207
208 /*========================= End of Function ========================*/
209
210 /*------------------------------------------------------------------*/
211 /*                                                                  */
212 /* Name         - throw_exception.                                  */
213 /*                                                                  */
214 /* Function     - Raise an exception based on the parameters passed.*/
215 /*                                                                  */
216 /*------------------------------------------------------------------*/
217
218 static void
219 throw_exception (MonoObject *exc, unsigned long ip, unsigned long sp, 
220                  gulong *int_regs, gdouble *fp_regs, gulong *acc_regs, 
221                  guint fpc, gboolean rethrow)
222 {
223         MonoContext ctx;
224         int iReg;
225         
226         memset(&ctx, 0, sizeof(ctx));
227
228         getcontext(&ctx);
229
230         /* adjust eip so that it point into the call instruction */
231         ip -= 6;
232
233         for (iReg = 0; iReg < 16; iReg++) {
234                 ctx.uc_mcontext.gregs[iReg]         = int_regs[iReg];
235                 ctx.uc_mcontext.fpregs.fprs[iReg].d = fp_regs[iReg];
236                 ctx.uc_mcontext.aregs[iReg]         = acc_regs[iReg];
237         }
238
239         ctx.uc_mcontext.fpregs.fpc = fpc;
240
241         MONO_CONTEXT_SET_BP (&ctx, sp);
242         MONO_CONTEXT_SET_IP (&ctx, ip);
243         
244         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
245                 MonoException *mono_ex = (MonoException*)exc;
246                 if (!rethrow)
247                         mono_ex->stack_trace = NULL;
248         }
249         mono_arch_handle_exception (&ctx, exc, FALSE);
250         setcontext(&ctx);
251
252         g_assert_not_reached ();
253 }
254
255 /*========================= End of Function ========================*/
256
257 /*------------------------------------------------------------------*/
258 /*                                                                  */
259 /* Name         - get_throw_exception_generic                       */
260 /*                                                                  */
261 /* Function     - Return a function pointer which can be used to    */
262 /*                raise exceptions. The returned function has the   */
263 /*                following signature:                              */
264 /*                void (*func) (MonoException *exc); or,            */
265 /*                void (*func) (char *exc_name);                    */
266 /*                                                                  */
267 /*------------------------------------------------------------------*/
268
269 static gpointer 
270 get_throw_exception_generic (guint8 *start, int size, 
271                              int by_name, gboolean rethrow)
272 {
273         guint8 *code;
274         int alloc_size, pos, i, offset;
275
276         code = start;
277
278         s390_stm (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
279         alloc_size = S390_ALIGN(S390_THROWSTACK_SIZE, S390_STACK_ALIGNMENT);
280         s390_lr   (code, s390_r14, STK_BASE);
281         s390_ahi  (code, STK_BASE, -alloc_size);
282         s390_st   (code, s390_r14, 0, STK_BASE, 0);
283         if (by_name) {
284                 s390_lr   (code, s390_r4, s390_r2);
285                 s390_bras (code, s390_r13, 6);
286                 s390_word (code, mono_defaults.corlib);
287                 s390_word (code, "System");
288                 s390_l    (code, s390_r2, 0, s390_r13, 0);
289                 s390_l    (code, s390_r3, 0, s390_r13, 4);
290                 offset = (guint32) S390_RELATIVE(mono_exception_from_name, code);
291                 s390_brasl(code, s390_r14, offset);
292         }
293         /*------------------------------------------------------*/
294         /* save the general registers on the stack              */
295         /*------------------------------------------------------*/
296         s390_stm (code, s390_r0, s390_r13, STK_BASE, S390_THROWSTACK_INTREGS);
297
298         s390_lr  (code, s390_r1, STK_BASE);
299         s390_ahi (code, s390_r1, alloc_size);
300         /*------------------------------------------------------*/
301         /* save the return address in the parameter register    */
302         /*------------------------------------------------------*/
303         s390_l   (code, s390_r3, 0, s390_r1, S390_RET_ADDR_OFFSET);
304
305         /*------------------------------------------------------*/
306         /* save the floating point registers                    */
307         /*------------------------------------------------------*/
308         pos = S390_THROWSTACK_FLTREGS;
309         for (i = 0; i < 16; ++i) {
310                 s390_std (code, i, 0,STK_BASE, pos);
311                 pos += sizeof (gdouble);
312         }
313         /*------------------------------------------------------*/
314         /* save the access registers                            */
315         /*------------------------------------------------------*/
316         s390_stam (code, s390_r0, s390_r15, STK_BASE, S390_THROWSTACK_ACCREGS);
317
318         /*------------------------------------------------------*/
319         /* call throw_exception (exc, ip, sp, gr, fr, ar)       */
320         /* exc is already in place in r2                        */
321         /*------------------------------------------------------*/
322         s390_lr   (code, s390_r4, s390_r1);        /* caller sp */
323         /*------------------------------------------------------*/
324         /* pointer to the saved int regs                        */
325         /*------------------------------------------------------*/
326         s390_la   (code, s390_r5, 0, STK_BASE, S390_THROWSTACK_INTREGS);
327         s390_la   (code, s390_r6, 0, STK_BASE, S390_THROWSTACK_FLTREGS);
328         s390_la   (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_ACCREGS);
329         s390_st   (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_ACCPRM);
330         s390_stfpc(code, STK_BASE, S390_THROWSTACK_FPCPRM);
331         s390_lhi  (code, s390_r7, rethrow);
332         s390_st   (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_RETHROW);
333         offset = (guint32) S390_RELATIVE(throw_exception, code);
334         s390_brasl(code, s390_r14, offset);
335         /* we should never reach this breakpoint */
336         s390_break (code);
337         g_assert ((code - start) < size);
338         return start;
339 }
340
341 /*========================= End of Function ========================*/
342
343 /*------------------------------------------------------------------*/
344 /*                                                                  */
345 /* Name         - arch_get_throw_exception                          */
346 /*                                                                  */
347 /* Function     - Return a function pointer which can be used to    */
348 /*                raise exceptions. The returned function has the   */
349 /*                following signature:                              */
350 /*                void (*func) (MonoException *exc);                */
351 /*                                                                  */
352 /*------------------------------------------------------------------*/
353
354 gpointer
355 mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot)
356 {
357         static guint8 *start;
358         static int inited = 0;
359
360         g_assert (!aot);
361         if (info)
362                 *info = NULL;
363
364         if (inited)
365                 return start;
366         start = mono_global_codeman_reserve (SZ_THROW);
367         get_throw_exception_generic (start, SZ_THROW, FALSE, FALSE);
368         inited = 1;
369         return start;
370 }
371
372 /*========================= End of Function ========================*/
373
374 /*------------------------------------------------------------------*/
375 /*                                                                  */
376 /* Name         - arch_get_rethrow_exception                        */
377 /*                                                                  */
378 /* Function     - Return a function pointer which can be used to    */
379 /*                raise exceptions. The returned function has the   */
380 /*                following signature:                              */
381 /*                void (*func) (MonoException *exc);                */
382 /*                                                                  */
383 /*------------------------------------------------------------------*/
384
385 gpointer 
386 mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot)
387 {
388         static guint8 *start;
389         static int inited = 0;
390
391         g_assert (!aot);
392         if (info)
393                 *info = NULL;
394
395         if (inited)
396                 return start;
397         start = mono_global_codeman_reserve (SZ_THROW);
398         get_throw_exception_generic (start, SZ_THROW, FALSE, TRUE);
399         inited = 1;
400         return start;
401 }
402
403 /*========================= End of Function ========================*/
404
405 /*------------------------------------------------------------------*/
406 /*                                                                  */
407 /* Name         - arch_get_throw_exception_by_name                  */
408 /*                                                                  */
409 /* Function     - Return a function pointer which can be used to    */
410 /*                raise corlib exceptions. The return function has  */
411 /*                the following signature:                          */
412 /*                void (*func) (char *exc_name);                    */
413 /*                                                                  */
414 /*------------------------------------------------------------------*/
415
416 gpointer 
417 mono_arch_get_throw_exception_by_name (void)
418 {
419         static guint8 *start;
420         static int inited = 0;
421
422         if (inited)
423                 return start;
424         start = mono_global_codeman_reserve (SZ_THROW);
425         get_throw_exception_generic (start, SZ_THROW, TRUE, FALSE);
426         inited = 1;
427         return start;
428 }       
429
430 /*========================= End of Function ========================*/
431
432 /*------------------------------------------------------------------*/
433 /*                                                                  */
434 /* Name         - mono_arch_find_jit_info                           */
435 /*                                                                  */
436 /* Function     - See exceptions-amd64.c for docs.                      */
437 /*                                                                  */
438 /*------------------------------------------------------------------*/
439
440 gboolean
441 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, 
442                                                          MonoJitInfo *ji, MonoContext *ctx, 
443                                                          MonoContext *new_ctx, MonoLMF **lmf, 
444                                                          StackFrameInfo *frame)
445 {
446         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
447         MonoS390StackFrame *sframe;
448
449         memset (frame, 0, sizeof (StackFrameInfo));
450         frame->ji = ji;
451         frame->managed = FALSE;
452
453         *new_ctx = *ctx;
454
455         if (ji != NULL) {
456                 gint32 address;
457
458                 frame->type = FRAME_TYPE_MANAGED;
459
460                 if (!ji->method->wrapper_type || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
461                         frame->managed = TRUE;
462
463                 if (*lmf && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->ebp)) {
464                         /* remove any unused lmf */
465                         *lmf = (*lmf)->previous_lmf;
466                 }
467
468                 address = (char *)ip - (char *)ji->code_start;
469
470                 sframe = (MonoS390StackFrame *) MONO_CONTEXT_GET_SP (ctx);
471                 MONO_CONTEXT_SET_BP (new_ctx, sframe->prev);
472                 sframe = (MonoS390StackFrame *) sframe->prev;
473                 MONO_CONTEXT_SET_IP (new_ctx, (guint8*)sframe->return_address - 2);
474                 memcpy (&new_ctx->uc_mcontext.gregs[6], sframe->regs, (8*sizeof(gint32)));
475                 return TRUE;
476         } else if (*lmf) {
477                 if (!(*lmf)->method)
478                         return FALSE;
479
480                 ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL);
481                 if (!ji) {
482                         // FIXME: This can happen with multiple appdomains (bug #444383)
483                         return FALSE;
484                 }
485
486                 frame->ji = ji;
487                 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
488
489                 memcpy(new_ctx->uc_mcontext.gregs, (*lmf)->gregs, sizeof((*lmf)->gregs));
490                 memcpy(new_ctx->uc_mcontext.fpregs.fprs, (*lmf)->fregs, sizeof((*lmf)->fregs));
491
492                 MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp);
493                 MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip - 2);
494                 *lmf = (*lmf)->previous_lmf;
495
496                 return TRUE;
497         }
498
499         return FALSE;
500 }
501
502 /*========================= End of Function ========================*/
503
504 /*------------------------------------------------------------------*/
505 /*                                                                  */
506 /* Name         - mono_arch_handle_exception                        */
507 /*                                                                  */
508 /* Function     - Handle an exception raised by the JIT code.       */
509 /*                                                                  */
510 /* Parameters   - ctx       - Saved processor state                 */
511 /*                obj       - The exception object                  */
512 /*                test_only - Only test if the exception is caught, */
513 /*                            but don't call handlers               */
514 /*                                                                  */
515 /*------------------------------------------------------------------*/
516
517 gboolean
518 mono_arch_handle_exception (void *uc, gpointer obj, gboolean test_only)
519 {
520         return mono_handle_exception (uc, obj, mono_arch_ip_from_context(uc), test_only);
521 }
522
523 /*========================= End of Function ========================*/
524
525 /*------------------------------------------------------------------*/
526 /*                                                                  */
527 /* Name         - mono_arch_ip_from_context                         */
528 /*                                                                  */
529 /* Function     - Return the instruction pointer from the context.  */
530 /*                                                                  */
531 /* Parameters   - sigctx    - Saved processor state                 */
532 /*                                                                  */
533 /*------------------------------------------------------------------*/
534
535 gpointer
536 mono_arch_ip_from_context (void *sigctx)
537 {
538         return context_get_ip (sigctx);
539 }
540
541
542 /*========================= End of Function ========================*/
543
544 /*------------------------------------------------------------------*/
545 /*                                                                  */
546 /* Name         - mono_arch_get_restore_context                    */
547 /*                                                                  */
548 /* Function     - Return the address of the routine that will rest- */
549 /*                ore the context.                                  */
550 /*                                                                  */
551 /*------------------------------------------------------------------*/
552
553 gpointer
554 mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
555 {
556         g_assert (!aot);
557         if (info)
558                 *info = NULL;
559
560         return setcontext;
561 }
562
563
564 /*========================= End of Function ========================*/
565
566 /*------------------------------------------------------------------*/
567 /*                                                                  */
568 /* Name         - mono_arch_is_int_overflow                         */
569 /*                                                                  */
570 /* Function     - Inspect the code that raised the SIGFPE signal    */
571 /*                to see if the DivideByZero or Arithmetic exception*/
572 /*                should be raised.                                 */
573 /*                                                                  */
574 /*------------------------------------------------------------------*/
575
576 gboolean
577 mono_arch_is_int_overflow (void *uc, void *info)
578 {
579         MonoContext *ctx;
580         guint8      *code;
581         guint32     *operand;
582         gboolean    arithExc = TRUE;
583         gint        regNo,
584                     offset;
585
586         ctx  = (MonoContext *) uc;
587         code =  (guint8 *) ((siginfo_t *)info)->si_addr;
588         /*----------------------------------------------------------*/
589         /* Divide operations are the only ones that will give the   */
590         /* divide by zero exception so just check for these ops.    */
591         /*----------------------------------------------------------*/
592         switch (code[0]) {
593                 case 0x1d :             /* Divide Register          */
594                         regNo = code[1] & 0x0f; 
595                         if (ctx->uc_mcontext.gregs[regNo] == 0)
596                                 arithExc = FALSE;
597                 break;
598                 case 0x5d :             /* Divide                   */
599                         regNo   = (code[2] & 0xf0 >> 8);        
600                         offset  = *((guint16 *) code+2) & 0x0fff;
601                         operand = (guint32*)(ctx->uc_mcontext.gregs[regNo] + offset);
602                         if (*operand == 0)
603                                 arithExc = FALSE; 
604                 break;
605                 case 0xb9 :             /* Divide logical Register? */
606                         if (code[1] == 0x97) {
607                                 regNo = (code[2] & 0xf0 >> 8);  
608                                 if (ctx->uc_mcontext.gregs[regNo] == 0)
609                                         arithExc = FALSE;
610                         }
611                 break;
612                 case 0xe3 :             /* Divide logical?          */
613                         if (code[1] == 0x97) {  
614                                 regNo   = (code[2] & 0xf0 >> 8);        
615                                 offset  = *((guint32 *) code+1) & 0x000fffff;
616                                 operand = (guint32*)(ctx->uc_mcontext.gregs[regNo] + offset);
617                                 if (*operand == 0)
618                                         arithExc = FALSE; 
619                         }
620                 break;
621                 default:
622                         arithExc = TRUE;
623         }
624         ctx->uc_mcontext.psw.addr = (guint32)code;
625         return (arithExc);
626 }
627
628 /*========================= End of Function ========================*/