http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58486

            Bug ID: 58486
           Summary: insufficient CFI generated for call-saved VFP
                    registers
           Product: gcc
           Version: 4.8.2
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: roland at gnu dot org
            Target: arm-linux-gnueabi

I think this bug exists in trunk and in all past versions (seen in 4.6, at
least), but I did the detailed testing on today's gcc-4_8-branch.

The DWARF CFI generated to describe the save/restore of the call-saved VFP
registers (d8-d15) is insufficient: it covers only half of each register.

Consider this test case:

    __attribute__((noinline)) void foo(void) {
      struct { unsigned i[2]; } x = { 0xaaaaaaaa, 0xbbbbbbbb };
      asm("vldr d8, %0; bkpt" :: "m" (x) : "d8");
    }

    __attribute__((noinline)) void bar(void) {
      struct { unsigned i[2]; } x = { 0xffffffff, 0xeeeeeeee };
      asm("vldr d8, %0" :: "m" (x) : "d8");
      foo();
    }

    int main(void) {
      bar();
      return 0;
    }

Compiled with: gcc -O2 -g -marm -mfpu=neon -mhard-float

This gdb session demonstrates the failure:
    $ cat > foo.x
    r
    i reg s17
    up
    i reg s17
    k
    q
    $ gdb -x foo.x foo
    GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
    Copyright (C) 2012 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later
<http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "arm-linux-gnueabihf".
    For bug reporting instructions, please see:
    <http://bugs.launchpad.net/gdb-linaro/>...
    Reading symbols from /home/user/mcgrathr/foo...done.

    Program received signal SIGTRAP, Trace/breakpoint trap.
    0x0000838c in foo () at foo.c:3
    3      asm("vldr d8, %0; bkpt" :: "m" (x) : "d8");
    s17            -0.00572916633    (raw 0xbbbbbbbb)
    #1  0x000083c0 in bar () at foo.c:9
    9      foo();
    s17            -0.00572916633    (raw 0xbbbbbbbb)
    Kill the program being debugged? (y or n) [answered Y; input not from
terminal]

The second display of s17 should show 0xeeeeeeee, not 0xbbbbbbbb.

Examination of the prologue code shows:

    @ for foo
    fstmfdd    sp!, {d8}
    .cfi_def_cfa_offset 8
    .cfi_offset 80, -8

    @ for bar
    fstmfdd    sp!, {d8}
    .cfi_def_cfa_offset 12
    .cfi_offset 80, -12

The detailed analysis:

The 64-bit VFP registers d0-d15 use the same space as the 32-bit VFP
registers s0-s31.  Hence, d8 is the same as the pair {s16,s17}.

80 is the DWARF register number for the 32-bit register s16.  So this CFI
describes restoring only s16 but not s17, i.e. only half of d8, while the
code uses the full d8 register.

The spec at:
   
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040b/IHI0040B_aadwarf.pdf
says 64-95 are obsolescent DWARF register numbers for 32-bit registers
s0-s31.  It recommends instead using the newly-assigned numbers 256-271 for
the 64-bit registers d0-d15, and describing e.g. s16 as number 264 (d8)
with DW_OP_piece to slice it in half (not relevant in CFI).

With the GDB version I have on hand, register number 264 for d8 does work
correctly.  I'm not sure if there are older GDB versions that fail to
recognize that number.  To be compatible with an older debugger that
doesn't know the 264+ range of DWARF register numbers, the other option is
to emit CFI for d8 as the two registers s16 and s17, e.g. (for foo above):

    .cfi_offset 80, -8
    .cfi_offset 81, -4

This also works with the GDB I have on hand.

Reply via email to