New tests.
[mono.git] / mono / mini / exceptions-s390x.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(gint32)))
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(gint32))
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(gint32)))
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/s390x/s390x-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-s390x.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 (void)
109 {
110         static guint8 *start;
111         static int inited = 0;
112         guint8 *code;
113         int alloc_size, pos, i;
114
115         if (inited)
116                 return start;
117
118         inited = 1;
119         /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */
120         code = start = mono_global_codeman_reserve (512);
121
122         s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
123         s390_lgr  (code, s390_r14, STK_BASE);
124         alloc_size = S390_ALIGN(S390_CALLFILTER_SIZE, S390_STACK_ALIGNMENT);
125         s390_aghi (code, STK_BASE, -alloc_size);
126         s390_stg  (code, s390_r14, 0, STK_BASE, 0);
127
128         /*------------------------------------------------------*/
129         /* save general registers on stack                      */
130         /*------------------------------------------------------*/
131         s390_stmg (code, s390_r0, s390_r13, STK_BASE, S390_CALLFILTER_INTREGS);
132
133         /*------------------------------------------------------*/
134         /* save floating point registers on stack               */
135         /*------------------------------------------------------*/
136 //      pos = S390_CALLFILTER_FLTREGS;
137 //      for (i = 0; i < 16; ++i) {
138 //              s390_std (code, i, 0, STK_BASE, pos);
139 //              pos += sizeof (gdouble);
140 //      }
141
142         /*------------------------------------------------------*/
143         /* save access registers on stack                       */
144         /*------------------------------------------------------*/
145 //      s390_stam (code, s390_a0, s390_a15, STK_BASE, S390_CALLFILTER_ACCREGS);
146
147         /*------------------------------------------------------*/
148         /* Get A(Context)                                       */
149         /*------------------------------------------------------*/
150         s390_lgr  (code, s390_r13, s390_r2);
151
152         /*------------------------------------------------------*/
153         /* Get A(Handler Entry Point)                           */
154         /*------------------------------------------------------*/
155         s390_lgr  (code, s390_r0, s390_r3);
156
157         /*------------------------------------------------------*/
158         /* Set parameter register with Exception                */
159         /*------------------------------------------------------*/
160         s390_lgr  (code, s390_r2, s390_r4);
161
162         /*------------------------------------------------------*/
163         /* Load all registers with values from the context      */
164         /*------------------------------------------------------*/
165         s390_lmg  (code, s390_r3, s390_r12, s390_r13, 
166                    G_STRUCT_OFFSET(MonoContext, uc_mcontext.gregs[3]));
167         pos = G_STRUCT_OFFSET(MonoContext, uc_mcontext.fpregs.fprs[0]);
168         for (i = 0; i < 16; ++i) {
169                 s390_ld  (code, i, 0, s390_r13, pos);
170                 pos += sizeof(gdouble);
171         }
172         
173         /*------------------------------------------------------*/
174         /* Point at the copied stack frame and call the filter  */
175         /*------------------------------------------------------*/
176         s390_lgr  (code, s390_r1, s390_r0);
177         s390_basr (code, s390_r14, s390_r1);
178
179         /*------------------------------------------------------*/
180         /* Save return value                                    */
181         /*------------------------------------------------------*/
182         s390_lgr  (code, s390_r14, s390_r2);
183
184         /*------------------------------------------------------*/
185         /* Restore all the regs from the stack                  */
186         /*------------------------------------------------------*/
187         s390_lmg  (code, s390_r0, s390_r13, STK_BASE, S390_CALLFILTER_INTREGS);
188 //      pos = S390_CALLFILTER_FLTREGS;
189 //      for (i = 0; i < 16; ++i) {
190 //              s390_ld (code, i, 0, STK_BASE, pos);
191 //              pos += sizeof (gdouble);
192 //      }
193
194         s390_lgr  (code, s390_r2, s390_r14);
195 //      s390_lam  (code, s390_a0, s390_a15, STK_BASE, S390_CALLFILTER_ACCREGS);
196         s390_aghi (code, s390_r15, alloc_size);
197         s390_lmg  (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
198         s390_br   (code, s390_r14);
199
200         g_assert ((code - start) < SZ_THROW); 
201         return start;
202 }
203
204 /*========================= End of Function ========================*/
205
206 /*------------------------------------------------------------------*/
207 /*                                                                  */
208 /* Name         - throw_exception.                                  */
209 /*                                                                  */
210 /* Function     - Raise an exception based on the parameters passed.*/
211 /*                                                                  */
212 /*------------------------------------------------------------------*/
213
214 static void
215 throw_exception (MonoObject *exc, unsigned long ip, unsigned long sp, 
216                  gulong *int_regs, gdouble *fp_regs, gint32 *acc_regs, 
217                  guint fpc, gboolean rethrow)
218 {
219         MonoContext ctx;
220         int iReg;
221         
222         memset(&ctx, 0, sizeof(ctx));
223
224         getcontext(&ctx);
225
226         /* adjust eip so that it point into the call instruction */
227         ip -= 6;
228
229         for (iReg = 0; iReg < 16; iReg++) {
230                 ctx.uc_mcontext.gregs[iReg]         = int_regs[iReg];
231                 ctx.uc_mcontext.fpregs.fprs[iReg].d = fp_regs[iReg];
232                 ctx.uc_mcontext.aregs[iReg]         = acc_regs[iReg];
233         }
234
235         ctx.uc_mcontext.fpregs.fpc = fpc;
236
237         MONO_CONTEXT_SET_BP (&ctx, sp);
238         MONO_CONTEXT_SET_IP (&ctx, ip);
239         
240         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
241                 MonoException *mono_ex = (MonoException*)exc;
242                 if (!rethrow)
243                         mono_ex->stack_trace = NULL;
244         }
245         mono_arch_handle_exception (&ctx, exc, FALSE);
246         setcontext(&ctx);
247
248         g_assert_not_reached ();
249 }
250
251 /*========================= End of Function ========================*/
252
253 /*------------------------------------------------------------------*/
254 /*                                                                  */
255 /* Name         - get_throw_exception_generic                       */
256 /*                                                                  */
257 /* Function     - Return a function pointer which can be used to    */
258 /*                raise exceptions. The returned function has the   */
259 /*                following signature:                              */
260 /*                void (*func) (MonoException *exc); or,            */
261 /*                void (*func) (char *exc_name);                    */
262 /*                                                                  */
263 /*------------------------------------------------------------------*/
264
265 static gpointer 
266 get_throw_exception_generic (guint8 *start, int size, 
267                              int by_name, gboolean rethrow)
268 {
269         guint8 *code;
270         int alloc_size, pos, i;
271
272         code = start;
273
274         s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET);
275         alloc_size = S390_ALIGN(S390_THROWSTACK_SIZE, S390_STACK_ALIGNMENT);
276         s390_lgr  (code, s390_r14, STK_BASE);
277         s390_aghi (code, STK_BASE, -alloc_size);
278         s390_stg  (code, s390_r14, 0, STK_BASE, 0);
279         if (by_name) {
280                 s390_lgr  (code, s390_r4, s390_r2);
281                 s390_basr (code, s390_r13, 0);
282                 s390_j    (code, 14);
283                 s390_llong(code, mono_defaults.corlib);
284                 s390_llong(code, "System");
285                 s390_llong(code, mono_exception_from_name);
286                 s390_lg   (code, s390_r2, 0, s390_r13, 4);
287                 s390_lg   (code, s390_r3, 0, s390_r13, 12);
288                 s390_lg   (code, s390_r1, 0, s390_r13, 20);
289                 s390_basr (code, s390_r14, s390_r1);
290         }
291         /*------------------------------------------------------*/
292         /* save the general registers on the stack              */
293         /*------------------------------------------------------*/
294         s390_stmg (code, s390_r0, s390_r13, STK_BASE, S390_THROWSTACK_INTREGS);
295
296         s390_lgr  (code, s390_r1, STK_BASE);
297         s390_aghi (code, s390_r1, alloc_size);
298         /*------------------------------------------------------*/
299         /* save the return address in the parameter register    */
300         /*------------------------------------------------------*/
301         s390_lg   (code, s390_r3, 0, s390_r1, S390_RET_ADDR_OFFSET);
302
303         /*------------------------------------------------------*/
304         /* save the floating point registers                    */
305         /*------------------------------------------------------*/
306         pos = S390_THROWSTACK_FLTREGS;
307         for (i = 0; i < 16; ++i) {
308                 s390_std (code, i, 0, STK_BASE, pos);
309                 pos += sizeof (gdouble);
310         }
311         /*------------------------------------------------------*/
312         /* save the access registers                            */
313         /*------------------------------------------------------*/
314         s390_stam (code, s390_r0, s390_r15, STK_BASE, S390_THROWSTACK_ACCREGS);
315
316         /*------------------------------------------------------*/
317         /* call throw_exception (exc, ip, sp, gr, fr, ar)       */
318         /* exc is already in place in r2                        */
319         /*------------------------------------------------------*/
320         s390_lgr  (code, s390_r4, s390_r1);        /* caller sp */
321         /*------------------------------------------------------*/
322         /* pointer to the saved int regs                        */
323         /*------------------------------------------------------*/
324         s390_la   (code, s390_r5, 0, STK_BASE, S390_THROWSTACK_INTREGS);
325         s390_la   (code, s390_r6, 0, STK_BASE, S390_THROWSTACK_FLTREGS);
326         s390_la   (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_ACCREGS);
327         s390_stg  (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_ACCPRM);
328         s390_stfpc(code, STK_BASE, S390_THROWSTACK_FPCPRM);
329         s390_lghi (code, s390_r7, rethrow);
330         s390_stg  (code, s390_r7, 0, STK_BASE, S390_THROWSTACK_RETHROW);
331         s390_basr (code, s390_r13, 0);
332         s390_j    (code, 6);
333         s390_llong(code, throw_exception);
334         s390_lg   (code, s390_r1, 0, s390_r13, 4);
335         s390_basr (code, s390_r14, s390_r1);
336         /* we should never reach this breakpoint */
337         s390_break (code);
338         g_assert ((code - start) < size);
339         return start;
340 }
341
342 /*========================= End of Function ========================*/
343
344 /*------------------------------------------------------------------*/
345 /*                                                                  */
346 /* Name         - arch_get_throw_exception                          */
347 /*                                                                  */
348 /* Function     - Return a function pointer which can be used to    */
349 /*                raise exceptions. The returned function has the   */
350 /*                following signature:                              */
351 /*                void (*func) (MonoException *exc);                */
352 /*                                                                  */
353 /*------------------------------------------------------------------*/
354
355 gpointer 
356 mono_arch_get_throw_exception (void)
357 {
358         static guint8 *start;
359         static int inited = 0;
360
361         if (inited)
362                 return start;
363         start = mono_global_codeman_reserve (SZ_THROW);
364         get_throw_exception_generic (start, SZ_THROW, FALSE, FALSE);
365         inited = 1;
366         return start;
367 }
368
369 /*========================= End of Function ========================*/
370
371 /*------------------------------------------------------------------*/
372 /*                                                                  */
373 /* Name         - arch_get_rethrow_exception                        */
374 /*                                                                  */
375 /* Function     - Return a function pointer which can be used to    */
376 /*                raise exceptions. The returned function has the   */
377 /*                following signature:                              */
378 /*                void (*func) (MonoException *exc);                */
379 /*                                                                  */
380 /*------------------------------------------------------------------*/
381
382 gpointer 
383 mono_arch_get_rethrow_exception (void)
384 {
385         static guint8 *start;
386         static int inited = 0;
387
388         if (inited)
389                 return start;
390         start = mono_global_codeman_reserve (SZ_THROW);
391         get_throw_exception_generic (start, SZ_THROW, FALSE, TRUE);
392         inited = 1;
393         return start;
394 }
395
396 /*========================= End of Function ========================*/
397
398 /*------------------------------------------------------------------*/
399 /*                                                                  */
400 /* Name         - arch_get_throw_exception_by_name                  */
401 /*                                                                  */
402 /* Function     - Return a function pointer which can be used to    */
403 /*                raise corlib exceptions. The return function has  */
404 /*                the following signature:                          */
405 /*                void (*func) (char *exc_name);                    */
406 /*                                                                  */
407 /*------------------------------------------------------------------*/
408
409 gpointer 
410 mono_arch_get_throw_exception_by_name (void)
411 {
412         static guint8 *start;
413         static int inited = 0;
414
415         if (inited)
416                 return start;
417         start = mono_global_codeman_reserve (SZ_THROW);
418         get_throw_exception_generic (start, SZ_THROW, TRUE, FALSE);
419         inited = 1;
420         return start;
421 }       
422
423 /*========================= End of Function ========================*/
424
425 /*------------------------------------------------------------------*/
426 /*                                                                  */
427 /* Name         - mono_arch_find_jit_info                           */
428 /*                                                                  */
429 /* Function     - This function is used to gather information from  */
430 /*                @ctx. It returns the MonoJitInfo of the corres-   */
431 /*                ponding function, unwinds one stack frame and     */
432 /*                stores the resulting context into @new_ctx. It    */
433 /*                also stores a string describing the stack location*/
434 /*                into @trace (if not NULL), and modifies the @lmf  */
435 /*                if necessary. @native_offset returns the IP off-  */
436 /*                set from the start of the function or -1 if that  */
437 /*                information is not available.                     */
438 /*                                                                  */
439 /*------------------------------------------------------------------*/
440
441 MonoJitInfo *
442 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, 
443                          MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
444                          MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
445 {
446         MonoJitInfo *ji;
447         gpointer ip = (gpointer) MONO_CONTEXT_GET_IP (ctx);
448         MonoS390StackFrame *sframe;
449
450         if (prev_ji && 
451             (ip >= prev_ji->code_start && 
452             ((guint8 *) ip <= ((guint8 *) prev_ji->code_start) + prev_ji->code_size)))
453                 ji = prev_ji;
454         else
455                 ji = mono_jit_info_table_find (domain, ip);
456
457         if (managed)
458                 *managed = FALSE;
459
460         if (ji != NULL) {
461                 gint64 address;
462
463                 *new_ctx = *ctx;
464
465                 if (*lmf && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->ebp)) {
466                         /* remove any unused lmf */
467                         *lmf = (*lmf)->previous_lmf;
468                 }
469
470                 address = (char *)ip - (char *)ji->code_start;
471
472                 if (managed)
473                         if (!ji->method->wrapper_type)
474                                 *managed = TRUE;
475
476                 sframe = (MonoS390StackFrame *) MONO_CONTEXT_GET_SP (ctx);
477                 MONO_CONTEXT_SET_BP (new_ctx, sframe->prev);
478                 sframe = (MonoS390StackFrame *) sframe->prev;
479                 MONO_CONTEXT_SET_IP (new_ctx, sframe->return_address);
480                 memcpy (&new_ctx->uc_mcontext.gregs[6], sframe->regs, (8*sizeof(gint64)));
481                 return ji;
482
483         } else if (*lmf) {
484                 
485                 *new_ctx = *ctx;
486
487                 if (!(*lmf)->method)
488                         return (gpointer)-1;
489
490                 if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
491                 } else {
492                         memset (res, 0, MONO_SIZEOF_JIT_INFO);
493                         res->method = (*lmf)->method;
494                 }
495
496                 memcpy(new_ctx->uc_mcontext.gregs, (*lmf)->gregs, sizeof((*lmf)->gregs));
497                 memcpy(new_ctx->uc_mcontext.fpregs.fprs, (*lmf)->fregs, sizeof((*lmf)->fregs));
498
499                 MONO_CONTEXT_SET_BP (new_ctx, (*lmf)->ebp);
500                 MONO_CONTEXT_SET_IP (new_ctx, (*lmf)->eip);
501                 *lmf = (*lmf)->previous_lmf;
502
503                 return ji ? ji : res;
504         }
505
506         return NULL;
507 }
508
509 /*========================= End of Function ========================*/
510
511 /*------------------------------------------------------------------*/
512 /*                                                                  */
513 /* Name         - mono_arch_handle_exception                        */
514 /*                                                                  */
515 /* Function     - Handle an exception raised by the JIT code.       */
516 /*                                                                  */
517 /* Parameters   - ctx       - Saved processor state                 */
518 /*                obj       - The exception object                  */
519 /*                test_only - Only test if the exception is caught, */
520 /*                            but don't call handlers               */
521 /*                                                                  */
522 /*------------------------------------------------------------------*/
523
524 gboolean
525 mono_arch_handle_exception (void *uc, gpointer obj, gboolean test_only)
526 {
527         return mono_handle_exception (uc, obj, mono_arch_ip_from_context(uc), test_only);
528 }
529
530 /*========================= End of Function ========================*/
531
532 /*------------------------------------------------------------------*/
533 /*                                                                  */
534 /* Name         - mono_arch_ip_from_context                         */
535 /*                                                                  */
536 /* Function     - Return the instruction pointer from the context.  */
537 /*                                                                  */
538 /* Parameters   - sigctx    - Saved processor state                 */
539 /*                                                                  */
540 /*------------------------------------------------------------------*/
541
542 gpointer
543 mono_arch_ip_from_context (void *sigctx)
544 {
545         return ((gpointer) MONO_CONTEXT_GET_IP(((MonoContext *) sigctx)));
546 }
547
548
549 /*========================= End of Function ========================*/
550
551 /*------------------------------------------------------------------*/
552 /*                                                                  */
553 /* Name         - mono_arch_get_restore_context                     */
554 /*                                                                  */
555 /* Function     - Return the address of the routine that will rest- */
556 /*                ore the context.                                  */
557 /*                                                                  */
558 /*------------------------------------------------------------------*/
559
560 gpointer
561 mono_arch_get_restore_context ()
562 {
563         return setcontext;
564 }
565
566
567 /*========================= End of Function ========================*/
568
569 /*------------------------------------------------------------------*/
570 /*                                                                  */
571 /* Name         - mono_arch_is_int_overflow                         */
572 /*                                                                  */
573 /* Function     - Inspect the code that raised the SIGFPE signal    */
574 /*                to see if the DivideByZero or Arithmetic exception*/
575 /*                should be raised.                                 */
576 /*                                                                  */
577 /*------------------------------------------------------------------*/
578
579 gboolean
580 mono_arch_is_int_overflow (void *uc, void *info)
581 {
582         MonoContext *ctx;
583         guint8      *code;
584         guint64     *operand;
585         gboolean    arithExc = TRUE;
586         gint        regNo,
587                     idxNo,
588                     offset;
589
590         ctx  = (MonoContext *) uc;
591         code =  (guint8 *) ((siginfo_t *)info)->si_addr;
592         /*----------------------------------------------------------*/
593         /* Divide operations are the only ones that will give the   */
594         /* divide by zero exception so just check for these ops.    */
595         /*----------------------------------------------------------*/
596         switch (code[0]) {
597                 case 0x1d :             /* Divide Register          */
598                         regNo = code[1] & 0x0f; 
599                         if (ctx->uc_mcontext.gregs[regNo] == 0)
600                                 arithExc = FALSE;
601                 break;
602                 case 0x5d :             /* Divide                   */
603                         regNo   = (code[2] & 0xf0 >> 8);        
604                         idxNo   = (code[1] & 0x0f);
605                         offset  = *((guint16 *) code+2) & 0x0fff;
606                         operand = (guint64*)(ctx->uc_mcontext.gregs[regNo] + offset);
607                         if (idxNo != 0)
608                                 operand += ctx->uc_mcontext.gregs[idxNo];
609                         if (*operand == 0)
610                                 arithExc = FALSE; 
611                 break;
612                 case 0xb9 :             /* DL[GR] or DS[GR]         */
613                         if ((code[1] == 0x97) || (code[1] == 0x87) ||
614                             (code[1] == 0x0d) || (code[1] == 0x1d)) {
615                                 regNo = (code[3] & 0x0f);
616                                 if (ctx->uc_mcontext.gregs[regNo] == 0)
617                                         arithExc = FALSE;
618                         }
619                 break;
620                 case 0xe3 :             /* DL[G] | DS[G]            */
621                         if ((code[5] == 0x97) || (code[5] == 0x87) ||
622                             (code[5] == 0x0d) || (code[5] == 0x1d)) {
623                                 regNo   = (code[2] & 0xf0 >> 8);        
624                                 idxNo   = (code[1] & 0x0f);
625                                 offset  = (code[2] & 0x0f << 8) + 
626                                           code[3] + (code[4] << 12);
627                                 operand = (guint64*)(ctx->uc_mcontext.gregs[regNo] + offset);
628                                 if (idxNo != 0)
629                                         operand += ctx->uc_mcontext.gregs[idxNo];
630                                 if (*operand == 0)
631                                         arithExc = FALSE; 
632                         }
633                 break;
634                 default:
635                         arithExc = TRUE;
636         }
637         ctx->uc_mcontext.psw.addr = (guint64)code;
638         return (arithExc);
639 }
640
641 /*========================= End of Function ========================*/