ARM Technical Support Knowledge Articles

Trapping and identifying divide-by-zero errors

Applies to: ARM Developer Suite (ADS), RealView Developer Kit (RVDK) for OKI, RealView Developer Kit (RVDK) for ST, RealView Developer Kit for XScale (RVXDK), RealView Development Suite (RVDS)

Answer

It is often important to be able to eliminate any possible (accidental) division by zero errors in code, especially for embedded systems, which may not be able to recover easily. The following shows how to catch division by zero errors in:

  • integer division, and
  • (software) floating point division

and shows how to identify which line of your source code caused the error.

  1. Integer division

    Integer division is implemented by calling the C library functions __rt_sdiv and __rt_udiv. These check for divison by zero. If integer division by zero is detected, a branch to __rt_div0 is made. So to trap the division by zero, all you need to do is place a breakpoint on __rt_div0.

    On entry into __rt_div0, LR will contain the address of the instruction _after_ the call to the __rt_sdiv/__rt_udiv division routine in your application code. Therefore, to identify which line in your source code is the culprit, so you can simply look up the line of C code in the debugger at that address given by LR.

    If you need to examine parameters, etc, and save them for post-mortem debugging, you can intercept __rt_div0 like this:

             AREA foo, CODE
    
             IMPORT |$Super$$__rt_div0|
    EXPORT |$Sub$$__rt_div0|
    |$Sub$$__rt_div0|
     ;; Add code to save whatever registers you need here
    ;; Take care not to corrupt any needed registers
             B |$Super$$__rt_div0|
    
             END
    
  2. Floating point division (using the software floating point libraries)

    To find the address of the function in your application code which contains the arithmetic operation which resulted in the exception, simply place a breakpoint on the function "_fp_trapveneer", then look at LR.

    This is a function within the C library which is called if an exception occurs. On entry into this function, the registers are in the state they were when the exception occurred. So you can then simply view the registers when the breakpoint is hit.

    Example:

    ---- main.c ----
    #include <stdio.h>
    #include <fenv.h>
    int main(void)
    {
    float a, b, c;
    //  Trap the Invalid Operation exception and untrap all other exceptions:
    __ieee_status(FE_IEEE_MASK_ALL_EXCEPT, FE_IEEE_MASK_INVALID);
        c = 0;
    a = b / c;
    printf("b / c = %f, ", a);
        return 0;
    }
    ---- end main.c ----

    Built/executed with:

    armcc -g main.c -o main.axf (for RVCT 1.2 and earlier) or:

    armcc -g main.c -o main.axf --fpmode ieee_full (for RVCT 2.0 and later)

    armsd main.axf
    armsd: break @_fp_trapveneer
    armsd: go
    Breakpoint #1 at PC = 0x0000c77c (_fp_trapveneer + 0)
    _fp_trapveneer
    +0000 0x0000c77c: 0xe92d5000 .P-. : * stmfd r13!,{r12,r14}
    armsd: reg
    r0 = 0x00000000 r1 = 0x00000000 r2 = 0x00000000 r3 = 0x00000000
    r4 = 0x0000cb14 r5 = 0x00000000 r6 = 0x00000000 r7 = 0x00000000
    r8 = 0x00000000 r9 = 0x00000000 r10 = 0x00000000 r11 = 0x00000000
    r12 = 0x04000004 r13 = 0x07ffffe8 r14 = 0x000080c8
    pc = 0x0000c77c cpsr = %nzcvqIFt_SVC spsr = %nzcvqift_Reserved_00

    where r14 = LR = 0x80c8 = the address of the instruction after the "bl _f2d".

    If you need to examine parameters, etc, and save them for post-mortem debugging, you can intercept _fp_trapveneer like this:

             AREA foo, CODE
    
             IMPORT |$Super$$_fp_trapveneer|
    EXPORT |$Sub$$_fp_trapveneer|
    |$Sub$$_fp_trapveneer|
     ;; Add code to save whatever registers you need here
    ;; Take care not to corrupt any needed registers
             B |$Super$$_fp_trapveneer|
    
             END
    

Article last edited on: 2008-09-09 15:47:27

Rate this article

[Bad]
|
|
[Good]
Disagree? Move your mouse over the bar and click

Did you find this article helpful? Yes No

How can we improve this article?

Link to this article
Copyright © 2011 ARM Limited. All rights reserved. External (Open), Non-Confidential