This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug target/38952] [4.4 Regression] EH does not work.
- From: "dave dot korn dot cygwin at gmail dot com" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: 24 Jan 2009 00:10:44 -0000
- Subject: [Bug target/38952] [4.4 Regression] EH does not work.
- References: <bug-38952-9431@http.gcc.gnu.org/bugzilla/>
- Reply-to: gcc-bugzilla at gcc dot gnu dot org
------- Comment #5 from dave dot korn dot cygwin at gmail dot com 2009-01-24 00:10 -------
Here is a disassembly of the start of the main function:
(gdb) disass main
Dump of assembler code for function main:
0x00401070 <main+0>: push %ebp
0x00401071 <main+1>: mov %esp,%ebp
0x00401073 <main+3>: and $0xfffffff0,%esp
0x00401076 <main+6>: sub $0x60,%esp
0x00401079 <main+9>: mov %ebx,0x54(%esp)
0x0040107d <main+13>: mov %esi,0x58(%esp)
0x00401081 <main+17>: mov %edi,0x5c(%esp)
0x00401085 <main+21>: movl $0x407600,0x34(%esp)
0x0040108d <main+29>: movl $0x407bd4,0x38(%esp)
0x00401095 <main+37>: lea 0x3c(%esp),%eax
0x00401099 <main+41>: lea 0x50(%esp),%edx
0x0040109d <main+45>: mov %edx,(%eax)
0x0040109f <main+47>: movl $0x4010ec,0x4(%eax)
0x004010a6 <main+54>: mov %esp,0x8(%eax)
0x004010a9 <main+57>: lea 0x1c(%esp),%eax
0x004010ad <main+61>: mov %eax,(%esp)
0x004010b0 <main+64>: call 0x405068 <_Unwind_SjLj_Register>
0x004010b5 <main+69>: call 0x40515c <__main>
0x004010ba <main+74>: movl $0x4,(%esp)
0x004010c1 <main+81>: call 0x406b00 <__cxa_allocate_exception>
0x004010c6 <main+86>: movl $0x1,(%eax)
0x004010cc <main+92>: movl $0x0,0x8(%esp)
0x004010d4 <main+100>: movl $0x40e7e0,0x4(%esp)
0x004010dc <main+108>: mov %eax,(%esp)
0x004010df <main+111>: movl $0x1,0x20(%esp)
0x004010e7 <main+119>: call 0x4075a0 <__cxa_throw>
0x004010ec <main+124>: mov 0x24(%esp),%eax
0x004010f0 <main+128>: mov %eax,(%esp)
0x004010f3 <main+131>: call 0x406da0 <__cxa_begin_catch>
If we set a breakpoint on every function call, and run through it:
(gdb) r
Starting program: /win/i/FSF-Gcc/obj-sjlj/gcc/testsuite/g++/eh.exe
[New thread 648.0x754]
[New thread 648.0x31c]
Breakpoint 1, main () at ./eh.C:4
4 {
(gdb) print $esp
$2 = (void *) 0x22ccac
(gdb) c
Continuing.
Breakpoint 3, 0x004010b0 in main () at ./eh.C:4
4 {
(gdb) print $esp
$3 = (void *) 0x22cc40
(gdb) print $ebp
$14 = (void *) 0x22cca8
(gdb) c
Continuing.
Breakpoint 4, main () at ./eh.C:4
4 {
(gdb) print $ebp
$4 = (void *) 0x22cca8
(gdb) c
Continuing.
Breakpoint 5, 0x004010c1 in main () at ./eh.C:6
6 throw 1;
(gdb) print $ebp
$5 = (void *) 0x22cca8
(gdb) c
Continuing.
Breakpoint 6, 0x004010e7 in main () at ./eh.C:6
6 throw 1;
(gdb) print $ebp
$6 = (void *) 0x22cca8
(gdb) c
Continuing.
Breakpoint 10, _Unwind_SjLj_RaiseException (exc=0x100325b8)
at /gnu/gcc/gcc/libgcc/../gcc/unwind-sjlj.c:148
148 if (use_fc_key < 0)
Current language: auto; currently c
(gdb) print $ebp
$7 = (void *) 0x22cc18
(gdb) c
Continuing.
Breakpoint 7, 0x004010f3 in main () at ./eh.C:8
8 catch (...) {
Current language: auto; currently c++
(gdb) print $ebp
$8 = (void *) 0x22cc90
(gdb) c
Continuing.
Breakpoint 8, 0x00401100 in main () at ./eh.C:8
8 catch (...) {
(gdb) print $ebp
$9 = (void *) 0x22cc90
(gdb) c
Continuing.
Breakpoint 9, 0x0040110c in main () at ./eh.C:8
8 catch (...) {
(gdb) print $ebp
$10 = (void *) 0x22cc90
(gdb) c
Continuing.
Breakpoint 11, 0x00401122 in main () at ./eh.C:11
11 }
(gdb) print $ebp
$11 = (void *) 0x22cc90
(gdb) c
Continuing.
Breakpoint 2, 0x00401125 in main () at ./eh.C:11
11 }
(gdb) print $ebp
$12 = (void *) 0x100324fa
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00000000 in ?? ()
(gdb)
... we can see that $ebp is correct right up until the call to __cxa_throw at
0x004010e7, but when we return to the catch landing site at 0x004010f3, $ebp is
incorrect.
This incorrect value is calculated in the code at the start of main(), where
the code generated by sjlj_emit_function_enter calls
expand_builtin_setjmp_setup to initialise the jbuf[] member of the struct
SjLj_Function_Context that it then passes to _Unwind_SjLj_Register. From that
call:
0x004010a9 <main+57>: lea 0x1c(%esp),%eax
0x004010ad <main+61>: mov %eax,(%esp)
0x004010b0 <main+64>: call 0x405068 <_Unwind_SjLj_Register>
the struct is at an offset of 0x1c on the stack. Looking at the memory dump,
just before the call:
0x22cc40: 0x0022cc5c 0xbdbdbdbd 0xbdbdbdbd 0xbdbdbdbd
0x22cc50: 0xbdbdbdbd 0xbdbdbdbd 0xbdbdbdbd 0xbdbdbdbd
0x22cc60: 0xbdbdbdbd 0xbdbdbdbd 0xbdbdbdbd 0xbdbdbdbd
0x22cc70: 0xbdbdbdbd 0x00407600 0x00407bd4 0x0022cc90
0x22cc80: 0x004010ec 0x0022cc40 0xbdbdbdbd 0xbdbdbdbd
0x22cc90: 0xbdbdbdbd 0x00000000 0x611021a0 0x0040546c
0x22cca0: 0xbdbdbdbd 0xbdbdbdbd 0x0022cd98 0x610060e8
0x22ccb0: 0x00000001 0x100324a0 0x10030090 0x60030000
.. shows that the struct has been initialised like so:
OFFS:0x001c: prev = 0xbdbdbdbd, call_Site 0xbdbdbdbd
OFFS:0x0024: data[4] = { 0xbdbdbdbd, 0xbdbdbdbd, 0xbdbdbdbd, 0xbdbdbdbd }
OFFS:0x0034: personality = 0x00407600 = <__gxx_personality_sj0>
OFFS:0x0038: lsda = 0x00407bd4 = <__DTOR_LIST__+16>: 0x010d00ff
OFFS:0x003c: jbuf = void*[5] at
0x22cc7c: 0x0022cc90
0x22cc80: 0x004010ec 0x0022cc40 0xbdbdbdbd 0xbdbdbdbd
(note that I manually filled the empty stack frame with 0xbd bytes immediately
after it was allocated in this run).
A comment in expand_builtin_setjmp_setup says
/* We store the frame pointer and the address of receiver_label in
the buffer and use the rest of it for the stack save area, which
is machine-dependent. */
and 0x004010ec is indeed the receiver_label, but 0x0022cc90 is not the frame
pointer. The code that initialises this struct is
0x00401085 <main+21>: movl $0x407600,0x34(%esp)
0x0040108d <main+29>: movl $0x407bd4,0x38(%esp)
0x00401095 <main+37>: lea 0x3c(%esp),%eax
0x00401099 <main+41>: lea 0x50(%esp),%edx
0x0040109d <main+45>: mov %edx,(%eax)
0x0040109f <main+47>: movl $0x4010ec,0x4(%eax)
0x004010a6 <main+54>: mov %esp,0x8(%eax)
and so it is clear that the "lea 0x50(%esp),%edx" is the source of the
incorrect value 0x0022cc90, that is stored into jbuf[0].
As this is an offset relative to the stack pointer, yet it originates in the
line
emit_move_insn (mem, targetm.builtin_setjmp_frame_value ());
I am working on the hypothesis that something has gone wrong with frame pointer
elimination.
--
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38952