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