This is the mail archive of the gdb-prs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug backtrace/10275] New: GCC-4.5 exposes apparent GDB mis-handling of DW_CFA_restore_state


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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]