MIPS division by zero and libgcj...
It appears that gcc configured for mipsel-linux will execute a "break 7" instruction on integer division by zero.
This causes the kernel (I am using 2.4.25) to send SIGTRAP.
Gcj when configured for this platform uses the -f-use-divide-subroutine option, causing it to never generate inline division instructions (nor the accompanying break 7), but instead call a runtime function that properly handles throwing ArithmeticException.
Q1: Is this behavior (use of break 7 and SIGTRAP) part of some ABI specification? I'll admit a bit of ignorance in this area.
Q2: Does anyone see any reason that libgcj should not be configured to handle the SIGTRAP and throw the ArithmeticException from the signal handler (similar to what is done on i386).
Q3: Will using SIGTRAP in this manner make debugging programs that divide things by zero very difficult to debug under gdb?
Q4: I appears that on the i386, a divide overflow causes SIGFPE. Why doesn't the mips-linux kernel sent SIGFPE on "break 7"
Q5: prims.cc in libgcj implies that we should be handling SIGFPE to do all this. If I make these changes, won't it be a little confusing that all references to SIGFPE are really SIGTRAP?
David Daney
Quoted 2 lines · David Daney
It appears that gcc configured for mipsel-linux will execute a "break 7" instruction on integer division by zero.
I thought that the MIPS never generated a hardware trap for division, but instead there was an assembler macro that did the test for overflow, and the "div" instruction actually generates this test inline. Maybe do a disassembly to check.
Quoted 9 lines
This causes the kernel (I am using 2.4.25) to send SIGTRAP.
Gcj when configured for this platform uses the -f-use-divide-subroutine option, causing it to never generate inline division instructions (nor the accompanying break 7), but instead call a runtime function that properly handles throwing ArithmeticException.
Q1: Is this behavior (use of break 7 and SIGTRAP) part of some ABI specification? I'll admit a bit of ignorance in this area.
See above.
Quoted 3 lines
Q2: Does anyone see any reason that libgcj should not be configured to handle the SIGTRAP and throw the ArithmeticException from the signal handler (similar to what is done on i386).
No, there's no reason not to do it. You'll have to write some hairy code to satisfy all the rules, though.
Quoted 2 lines
Q3: Will using SIGTRAP in this manner make debugging programs that divide things by zero very difficult to debug under gdb?
No.
Quoted 6 lines
Q4: I appears that on the i386, a divide overflow causes SIGFPE. Why doesn't the mips-linux kernel sent SIGFPE on "break 7"
Q5: prims.cc in libgcj implies that we should be handling SIGFPE to do all this. If I make these changes, won't it be a little confusing that all references to SIGFPE are really SIGTRAP?
Feel free to change the comments. :-)
Andrew.
Quoted 8 lines · Andrew Haley
Quoted 2 lines · David Daney
It appears that gcc configured for mipsel-linux will execute a "break 7" instruction on integer division by zero.
I thought that the MIPS never generated a hardware trap for division, but instead there was an assembler macro that did the test for overflow, and the "div" instruction actually generates this test inline. Maybe do a disassembly to check.
Here we are:
MIPS Dependent Features
--trap
--no-break
automatically macro expands certain division and multiplication instructions to check for overflow and division by zero. This option causes to generate code to take a trap exception rather than a break exception when an error is detected. The trap instructions are only supported at Instruction Set Architecture level 2 and higher.
--break
--no-trap
Generate code to take a break exception rather than a trap exception when an error is detected. This is the default.
Andrew.
Quoted 9 lines · Andrew Haley
Quoted 1 line · David Daney
It appears that gcc configured for mipsel-linux will execute a "break 7" instruction on integer division by zero.
I thought that the MIPS never generated a hardware trap for division, but instead there was an assembler macro that did the test for overflow, and the "div" instruction actually generates this test inline. Maybe do a disassembly to check.
MIPS div instructions never trap. However I think that GCC always emits things like this when it cannot determine that the divisor is non zero:
div $0,$17,$16
bne $16,$0,1f
nop
break 71:
Quoted 4 lines
Quoted 4 lines
This causes the kernel (I am using 2.4.25) to send SIGTRAP.
Gcj when configured for this platform uses the -f-use-divide-subroutine option, causing it to never generate inline division instructions (nor the accompanying break 7), but instead call a runtime function that properly handles throwing ArithmeticException.
Quoted 9 lines
Quoted 1 line
Q1: Is this behavior (use of break 7 and SIGTRAP) part of some ABI specification? I'll admit a bit of ignorance in this area.
See above.
Quoted 1 line
Q2: Does anyone see any reason that libgcj should not be configured to handle the SIGTRAP and throw the ArithmeticException from the signal handler (similar to what is done on i386).
No, there's no reason not to do it. You'll have to write some hairy code to satisfy all the rules, though.
What are the rules? Are they more complicated then throw an ArithmeticException when the divisor is zero?
Quoted 6 lines
Quoted 2 lines
Q3: Will using SIGTRAP in this manner make debugging programs that divide things by zero very difficult to debug under gdb?
No.
I have not tried it. But I think gdb uses "break" and SIGTRAP for breakpoints. Is it possible to get gdb to pass the signal to the debugee, so that it could be handled by the runtime support?
Quoted 13 lines · David Daney
Andrew Haley wrote:
MIPS div instructions never trap. However I think that GCC always emits things like this when it cannot determine that the divisor is non zero:
div $0,$17,$16 bne $16,$0,1f nop break 71:
Quoted 5 lines
Quoted 3 lines
No, there's no reason not to do it. You'll have to write some hairy code to satisfy all the rules, though.
What are the rules? Are they more complicated then throw an ArithmeticException when the divisor is zero?
Yes. You also have to do
if (dividend == (jint) 0x80000000L && divisor == -1)
return dividend;and not throw an exception.
Quoted 9 lines
Quoted 6 lines
Quoted 2 lines
Q3: Will using SIGTRAP in this manner make debugging programs that divide things by zero very difficult to debug under gdb?
No.
I have not tried it. But I think gdb uses "break" and SIGTRAP for breakpoints. Is it possible to get gdb to pass the signal to the debugee, so that it could be handled by the runtime support?
Well, gcj will generate either break or trap instructions. You can tell gdb to ignore either.
Andrew.
Quoted 16 lines · Andrew Haley
Quoted 15 lines · David Daney
Andrew Haley wrote:
MIPS div instructions never trap. However I think that GCC always emits things like this when it cannot determine that the divisor is non zero:
div $0,$17,$16 bne $16,$0,1f nop break 71:
Quoted 3 lines
No, there's no reason not to do it. You'll have to write some hairy code to satisfy all the rules, though.
Quoted 9 lines
Quoted 1 line
What are the rules? Are they more complicated then throw an ArithmeticException when the divisor is zero?
Yes. You also have to do
if (dividend == (jint)
0x80000000L&& divisor == -1)
return dividend;and not throw an exception.
That is evidently what you have to do on i386. MIPS gives the right answer without faulting (i.e. hitting the break 7).
David Daney.
Quoted 4 lines · Andrew Haley
I thought that the MIPS never generated a hardware trap for division, but instead there was an assembler macro that did the test for overflow, and the "div" instruction actually generates this test inline. Maybe do a disassembly to check.
Linux/MIPS's behaviour is consistent with all MIPS UNIX flavours I know of both those following the SysV ABI and others such as Ultrix.
Ralf
Quoted 4 lines · David Daney
It appears that gcc configured for mipsel-linux will execute a "break 7" instruction on integer division by zero.
This causes the kernel (I am using 2.4.25) to send SIGTRAP.
It looks like you have a problem in your configuration. A "break 7"
(or "teq <divisor>,$zero,7" -- but that's currently implemented in gas only) is indeed emitted and exectuted in the case of division by zero, but Linux has the ability to recognize this special break code and sends SIGFPE instead. There are actually two special codes defined, the other being "6" for an overflow. Both are handled by Linux, with si_code in struct siginfo being set to FPE_INTDIV or FPE_INTOVF, respectively. You can handle this appropriately in a signal handler.
Signature · 3 lines
+ Maciej W. Rozycki, Technical University of Gdansk, Poland + +--------------------------------------------------------------+ + e-mail: [email protected], PGP key available +
Quoted 10 lines · Maciej W. Rozycki
Quoted 5 lines · David Daney
It appears that gcc configured for mipsel-linux will execute a "break 7" instruction on integer division by zero.
This causes the kernel (I am using 2.4.25) to send SIGTRAP.
Quoted 8 lines
It looks like you have a problem in your configuration. A "break 7" (or "teq <divisor>,$zero,7" -- but that's currently implemented in gas only) is indeed emitted and exectuted in the case of division by zero, but
Linux has the ability to recognize this special break code and sends
SIGFPE instead. There are actually two special codes defined, the other
being "6" for an overflow. Both are handled by Linux, withsi_codein
struct siginfo being set toFPE_INTDIVorFPE_INTOVF, respectively. You
can handle this appropriately in a signal handler.
My kernel sources are from linux-mips.org, it is little-endian running on:
# cat /proc/cpuinfo system type : ATI-Xilleon processor : 0 cpu model : MIPS 4Kc V0.7 BogoMIPS : 299.00 wait instruction : yes microsecond timers : yes tlb_entries : 16 extra interrupt vector : yes hardware watchpoint : yes VCED exceptions : not available VCEI exceptions : not available
Could you point me to where in the kernel source this is handled? I will try to see what when wrong.
David Daney.
Quoted 2 lines · David Daney
Could you point me to where in the kernel source this is handled? I will try to see what when wrong.
For 2.4 it's arch/mips{,64}/kernel/traps.c, functions do_bp() anddo_tr().
Signature · 3 lines
+ Maciej W. Rozycki, Technical University of Gdansk, Poland + +--------------------------------------------------------------+ + e-mail: [email protected], PGP key available +