This is the mail archive of the
gdb-prs@sourceware.org
mailing list for the GDB project.
[Bug backtrace/10275] New: GCC-4.5 exposes apparent GDB mis-handling of DW_CFA_restore_state
- From: "ppluzhnikov at google dot com" <sourceware-bugzilla at sourceware dot org>
- To: gdb-prs at sourceware dot org
- Date: 12 Jun 2009 22:51:42 -0000
- Subject: [Bug backtrace/10275] New: GCC-4.5 exposes apparent GDB mis-handling of DW_CFA_restore_state
- Reply-to: sourceware-bugzilla at sourceware dot org
I noticed that GDB (6.8.50.20090612-cvs) can't unwind optimized code on
Linux/x86_64, compiled with SVN GCC 4.5 @148440
This is because GCC now uses DW_CFA_remember_state/DW_CFA_restore_state
and emits unwind info in function epilogues.
But (AFAICT) GDB isn't handing DW_CFA_remember_state/DW_CFA_restore_state
correctly.
In particular, DWARF3 standard reads:
The DW_CFA_remember_state instruction takes no operands. The required
action is to push the set of rules for every register onto an implicit
stack.
The DW_CFA_restore_state instruction takes no operands. The required
action is to pop the set of rules off the implicit stack and place them
in the current row.
It is slightly ambiguous whether CFA is included in "every register", but
Cary Coutant (member of the DWARF committee) tells me that that's likely
the intended interpretation (CFA being a "virtual register" included in
the unwind table), and that's what GCC is doing.
Here is hand-coded assembly modeled after what GCC is doing for optimized
code:
.text
.globl main
.func main
main: call foo
mov $0,%rax
ret
.endfunc
.func foo
foo: .cfi_startproc
push %rbp
.cfi_adjust_cfa_offset 8
mov %rsp,%rbp
.cfi_def_cfa_register %rbp
.cfi_remember_state
jmp 2f
1: mov %rbp,%rsp
.cfi_restore %rbp
pop %rbp
.cfi_adjust_cfa_offset -8
.cfi_def_cfa_register %rsp
ret
.cfi_restore_state
2: movq $0,%rax
movq $0,(%rax) /* crash here */
jmp 1b
.cfi_endproc
.endfunc
This produces the following unwind table:
00000018 00000024 0000001c FDE cie=00000000 pc=00400455..00400470
DW_CFA_advance_loc: 1 to 00400456
DW_CFA_def_cfa_offset: 16
DW_CFA_advance_loc: 3 to 00400459
DW_CFA_def_cfa_register: r6 (rbp)
DW_CFA_remember_state
DW_CFA_advance_loc: 5 to 0040045e
DW_CFA_restore: r6 (rbp)
DW_CFA_advance_loc: 1 to 0040045f
DW_CFA_def_cfa_offset: 8
DW_CFA_def_cfa_register: r7 (rsp)
DW_CFA_advance_loc: 1 to 00400460
DW_CFA_restore_state
DW_CFA_nop
GDB shows:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400467 in foo ()
Current language: auto; currently asm
(gdb) bt
#0 0x0000000000400467 in foo ()
#1 0x0000000000000000 in ?? ()
This is happening because in dwarf2-frame.c, upon seeing
DW_CFA_restore_state, fs->regs is restored, but fs->cfa_reg and
fs->cfa_offset are left alone with previous values (r7 and 8 respectively).
If I adjust cfa_reg to r6 and cfa_offset to 16 "by hand", then correct
stack trace is produced:
(gdb) bt
#0 0x0000000000400467 in foo ()
#1 0x000000000040044d in main ()
--
Summary: GCC-4.5 exposes apparent GDB mis-handling of
DW_CFA_restore_state
Product: gdb
Version: 6.8
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: backtrace
AssignedTo: unassigned at sourceware dot org
ReportedBy: ppluzhnikov at google dot com
CC: ccoutant at google dot com,gdb-prs at sourceware dot org
GCC build triplet: x86_64-unknown-linux-gnu
GCC host triplet: x86_64-unknown-linux-gnu
GCC target triplet: x86_64-unknown-linux-gnu
http://sourceware.org/bugzilla/show_bug.cgi?id=10275
------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.