5.57 Identification of software floating-point division-by-zero errors

You can use the C library helper function _fp_trapveneer() to identify the location of a software floating-point division-by-zero error.

_fp_trapveneer() is called whenever an exception occurs. On entry into this function, the state of the registers is unchanged from when the exception occurred. Therefore, to find the address of the function in the application code that contains the arithmetic operation that resulted in the exception, a breakpoint can be placed on the function _fp_trapveneer() and LR can be inspected.

For example, consider the following example C code:

#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_DIVBYZERO);
    c = 0;
    b = 5.366789;
    a = b / c;
    printf("b / c = %f, ", a); // trap division-by-zero error
    return 0;
}

This example code is compiled with the following command:

armcc --fpmode ieee_full

The compiled example disassembles to the following code:

main:
    0x000080E0 : PUSH     {r4,lr}
    0x000080E4 : MOV      r1,#0x200
    0x000080E8 : MOV      r0,#0x9f00
    0x000080EC : BL       __ieee_status ; 0xB9B8
    0x000080F0 : MOV      r4,#0
    0x000080F4 : LDR      r0,[pc,#40] ; [0x8124] = 0x891E2153
    0x000080F8 : LDR      r1,[pc,#40] ; [0x8128] = 0x40157797
    0x000080FC : BL       __aeabi_d2f ; 0xA948
    0x00008100 : MOV      r1,r4
    0x00008104 : BL       __aeabi_fdiv ; 0xB410
    0x00008108 : BL       __aeabi_f2d ; 0xB388
    0x0000810C : MOV      r2,r0
    0x00008110 : MOV      r3,r1
    0x00008114 : ADR      r0,{pc}+0x18 ; 0x812c
    0x00008118 : BL       __2printf ; 0x813C
    0x0000811C : MOV      r0,#0
    0x00008120 : POP      {r4,pc}
    0x00008124 : DCD      0x891E2153
    0x00008128 : DCD      0x40157797
    0x0000812C : DCD      0x202F2062
    0x00008130 : DCD      0x203D2063
    0x00008134 : DCD      0x202C6625
    0x00008138 : DCD      0x00000000

Placing a breakpoint on _fp_trapveneer() and executing the disassembly in the debug monitor produces:

> run
Execution stopped at breakpoint 1: S:0x0000BAC8
In _fp_trapveneer (no debug info)
S:0x0000BAC8   PUSH     {r12,lr}

Then, inspection of the registers shows:

  r0: 0x40ABBCBC     r1: 0x00000000     r2: 0x00000000     r3: 0x00000000
  r4: 0x0000C1DC     r5: 0x0000BD44     r6: 0x00000000     r7: 0x00000000
  r8: 0x00000000     r9: 0x00000000    r10: 0x0000BC1C    r11: 0x00000000
 r12: 0x08000004     SP: 0x0FFFFFF8     LR: 0x00008108     PC: 0x0000BAC8
CPSR: 0x000001D3

The address contained in the link register LR is set to 0x8108, the address of the instruction after the instruction BL __aeabi_fdiv that resulted in the exception.

Non-ConfidentialPDF file icon PDF versionARM DUI0472M
Copyright © 2010-2016 ARM Limited or its affiliates. All rights reserved.