[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

questions re SIGFPE



I'm working on an x86 port of Standard ML, ie, sml-nj, and I've run into 
trouble dealing with signals.

Specifically, what signals and signal codes are generated by integer divide by 
zero and overflow errors?

After looking at <sys/siginfo.h> and the FreeBSD and NetBSD code below (the 
result of applying the patches from the FreeBSD and NetBSD ports, which seem 
actively maintained, so I'm assuming it works), I tried

#    define INT_DIVZERO(s, c)	(((s) == SIGFPE) && ((c) == FPE_INTDIV))
#    define INT_OVFLW(s, c)	(((s) == SIGFPE) && ((c) == FPE_INTOVF))

(INT_DIVZERO(s,c) and INT_OVFLW(s,c) take (signal,code) as arguments.)

but the compile eventually fails with an "unexpected fault, signal = 8, code = 
0" message.

Using either of 

#    define INT_DIVZERO(s, c)	(((s) == SIGFPE) && ((c) == 0))
#    define INT_OVFLW(s, c)	(((s) == SIGFPE) && ((c) == FPE_INTOVF))

#    define INT_DIVZERO(s, c)	(((s) == SIGFPE)
#    define INT_OVFLW(s, c)	(((s) == SIGFPE) && ((c) == FPE_INTOVF))

gets me past that bump, but seems to result in the masking of an overflow 
error that stops the build a bit later:

Fault handler: sig = 8, code = 0, inML = 1

uncaught exception divide by zero
  raised at: <file wrapping.sml.bin>
             translate/wrapping.sml:119.10

Everything builds with

/* always tests negative? */
#    define INT_DIVZERO(s, c)   (((s) == SIGFPE) && ((c) == FPE_INTDIV)
/* c always 0? */
#    define INT_OVFLW(s, c)     (((s) == SIGFPE) && ((c) == 0))

but then, as might be expected, sml interprets divide by zero errors as 
overflows (it doesn't under Solaris or Linux, ie, the sml developers don't 
seem to intend it to).


Signal-handling code is completely new to me, so any help is much appreciated.

Thanks,
Jon


Free and NetBSD code fragments:

#  elif defined(OPSYS_FREEBSD)
    /** x86, FreeBSD **/
#    define SIG_FAULT1		SIGFPE
#    define INT_DIVZERO(s, c)	(((s) == SIGFPE) && ((c) == FPE_INTDIV))
#    define INT_OVFLW(s, c)	(((s) == SIGFPE) && ((c) == FPE_INTOVF))

#    define SIG_GetCode(info, scp)	(info)
#    define SIG_GetPC(scp)		((scp)->sc_pc)
#    define SIG_SetPC(scp, addr)	{ (scp)->sc_pc = (long)(addr); }
#    define SIG_ZeroLimitPtr(scp)	{ ML_X86Frame[LIMITPTR_X86OFFSET] = 0; }

     typedef void SigReturn_t;

#  elif defined(OPSYS_NETBSD)
    /** x86, NetBSD **/
/* NetBSD (including versions 1.0 and 1.1) generates SIGBUS rather
   than SIGFPE for overflows.  The real fix is a trivial change to
   kernel sources, which has already been reported (NetBSD internal
   problem identification "port-i386/1833"). 

   If you want to fix this on your NetBSD system.  Edit machdep.c in
   directory /sys/arch/i386/i386, and find the line

        setgate(&idt[  4], &IDTVEC(ofl),     0, SDT_SYS386TGT, SEL_KPL);

   Change SEL_KPL to SEL_UPL.  With SEL_KPL, the int overflow trap is
   not accessible at user level, and a protection fault occurs instead
   (thus the seg fault).  SEL_UPL will allow user processes to generate
   this trap.

   For the change to take effect, recompile your kernel, install it
   and reboot. */
#    define SIG_FAULT1		SIGFPE
#    define SIG_FAULT2		SIGBUS
#    define INT_DIVZERO(s, c)	0
#    define INT_OVFLW(s, c)	(((s) == SIGFPE) || ((s) == SIGBUS))

#    define SIG_GetCode(info, scp)	(info)
#    define SIG_GetPC(scp)		((scp)->sc_pc)
#    define SIG_SetPC(scp, addr)	{ (scp)->sc_pc = (long)(addr); }
#    define SIG_ZeroLimitPtr(scp)	{ ML_X86Frame[LIMITPTR_X86OFFSET] = 0; }

     typedef void SigReturn_t;



Visit your host, monkey.org