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