This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug c/13267] New: Bad DWARF info is generated for char variable pushed to stack
- From: "gcc-bugzilla at gcc dot gnu dot org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 2 Dec 2003 04:02:05 -0000
- Subject: [Bug c/13267] New: Bad DWARF info is generated for char variable pushed to stack
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
While chasing a gdb testsuite failure for the sh-elf toolchain, I
discovered a problem printing a local variable that appears to be a
generic gcc bug in how it generates DWARF info for the local variable.
I just tested the mips-elf toolchain and the bug also appears using
that toolchain. It probably affects all toolchains that support a big
endian target.
Environment:
System: Linux fred.ninemoons.com 2.4.20-20.9 #1 Mon Aug 18 11:27:43 EDT 2003 i686 athlon i386 GNU/Linux
Architecture: i686
host: i686-pc-linux-gnu
build: i686-pc-linux-gnu
target: mips-unknown-elf
configured with: /src/sourceware/gcc/gcc/configure -v --prefix=/usr/local/sourceware --target=mips-elf --enable-multilib --with-gnu-as --with-gnu-ld --with-newlib --enable-languages=c,c++
How-To-Repeat:
Consider the following code, simplified from some "scope" tests in the
gdb testsuite:
signed char bar (register signed char u)
{
return (u + 1);
}
signed char foo (register signed char u)
{
register signed char l = u;
l = bar (l);
return (l);
}
main ()
{
foo (3);
}
Note that:
(1) the register declarations are required to expose the bug. Without
them, the generated code and debug information is different and the
problem goes away.
(2) The example should be compiled without optimization.
(3) The problem is masked if the target is little endian. Toolchains
such as sh-elf or mips-elf which are bi-endian help to demonstrate this.
Here is an example using the sh-elf toolchain in big endian mode.
Note that the value of 'l' after being assigned from 'u' and before
calling bar() is printed as 0 and should be 3, the same as 'u':
$ sh-elf-gcc -g -m4 -mb -o b b.c
$ sh-elf-gdb b
GNU gdb 2003-11-29-cvs
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "--host=i686-pc-linux-gnu --target=sh-elf"...
(gdb) tar sim
Connected to the simulator.
(gdb) load
Loading section .init, size 0x36 vma 0x1000
Loading section .text, size 0x1900 vma 0x1040
Loading section .fini, size 0x2a vma 0x2940
Loading section .rodata, size 0x1e vma 0x296c
Loading section .data, size 0x798 vma 0x2a0c
Loading section .eh_frame, size 0x4 vma 0x31a4
Loading section .ctors, size 0x8 vma 0x31a8
Loading section .dtors, size 0x8 vma 0x31b0
Loading section .jcr, size 0x4 vma 0x31b8
Loading section .got, size 0xc vma 0x31bc
Loading section .stack, size 0x4 vma 0x30000
Start address 0x1040
Transfer rate: 68080 bits/sec.
(gdb) br foo
Breakpoint 1 at 0x1186: file b.c, line 8.
(gdb) run
Starting program: /tmp/b
Breakpoint 1, foo (u=3 '\003') at b.c:8
8 register signed char l = u;
(gdb) n
10 l = bar (l);
(gdb) p l
$1 = 0 '\0'
(gdb)
If however we use little endian mode, the value is printed correctly:
$ sh-elf-gcc -g -m4 -ml -o b b.c
$ sh-elf-gdb b
GNU gdb 2003-11-29-cvs
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "--host=i686-pc-linux-gnu --target=sh-elf"...
(gdb) tar sim
Connected to the simulator.
(gdb) load
Loading section .init, size 0x36 vma 0x1000
Loading section .text, size 0x1900 vma 0x1040
Loading section .fini, size 0x2a vma 0x2940
Loading section .rodata, size 0x1e vma 0x296c
Loading section .data, size 0x798 vma 0x2a0c
Loading section .eh_frame, size 0x4 vma 0x31a4
Loading section .ctors, size 0x8 vma 0x31a8
Loading section .dtors, size 0x8 vma 0x31b0
Loading section .jcr, size 0x4 vma 0x31b8
Loading section .got, size 0xc vma 0x31bc
Loading section .stack, size 0x4 vma 0x30000
Start address 0x1040
Transfer rate: 68080 bits/sec.
(gdb) br foo
Breakpoint 1 at 0x1186: file b.c, line 8.
(gdb) run
Starting program: /tmp/b
Breakpoint 1, foo (u=3 '\003') at b.c:8
8 register signed char l = u;
(gdb) n
10 l = bar (l);
(gdb) p l
$1 = 3 '\003'
(gdb)
The problem is that the live value of 'l' at the time we print it is
on the stack, and the address computed from the dwarf information is
for the lowest address of the 4 byte stack slot that holds the
character value. In the big endian case, this is for the most
significant byte, which is zero. In the little endian case, this is
for the least significant byte, which is 3.
Note also that the dwarf info is identical for either endian:
$ sh-elf-gcc -g -m4 -mb -c b.c
$ dwarfdump -a b.o >b.o.mb
$ sh-elf-gcc -g -m4 -ml -c b.c
$ dwarfdump -a b.o >b.o.ml
$ diff b.o.mb b.o.ml
The code is also identical except for a pseudo that indicates the
endianness:
$ sh-elf-gcc -g -m4 -mb -S b.c
$ mv b.s b.s.mb
$ sh-elf-gcc -g -m4 -ml -S b.c
$ mv b.s b.s.ml
$ diff b.s.mb b.s.ml
2a3
> .little
$ diff -c b.s.mb b.s.ml
*** b.s.mb 2003-11-29 13:00:08.000000000 -0700
--- b.s.ml 2003-11-29 13:00:16.000000000 -0700
***************
*** 1,5 ****
--- 1,6 ----
.file "b.c"
.text
+ .little
.section .debug_abbrev,"",@progbits
.Ldebug_abbrev0:
.section .debug_info,"",@progbits
$
For reference, here are the relevant parts of the dwarfdump output:
<1>< 107> DW_TAG_base_type
DW_AT_name signed char
DW_AT_byte_size 1
DW_AT_encoding DW_ATE_signed_char
<2>< 160> DW_TAG_variable
DW_AT_name l
DW_AT_decl_file 1 /tmp/b.c
DW_AT_decl_line 8
DW_AT_type <107>
DW_AT_location DW_OP_fbreg 0
My guess is that since gcc is generating the memory offset of a 1 byte
object relative to the frame pointer that the DW_AT_location for the
big endian case should be:
DW_AT_location DW_OP_fbreg 3
--
Summary: Bad DWARF info is generated for char variable pushed to
stack
Product: gcc
Version: 3.4
Status: UNCONFIRMED
Severity: critical
Priority: P2
Component: c
AssignedTo: unassigned at gcc dot gnu dot org
ReportedBy: fnf at ninemoons dot com
CC: gcc-bugs at gcc dot gnu dot org
GCC build triplet: i686-pc-linux-gnu
GCC host triplet: i686-pc-linux-gnu
GCC target triplet: mips-unknown-elf
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=13267