* Exception unwinding bug
@ 2002-02-07 8:50 Ed Maste
2002-04-25 2:55 ` Exception handling problem on x86-64 Bo Thorsen
0 siblings, 1 reply; 4+ messages in thread
From: Ed Maste @ 2002-02-07 8:50 UTC (permalink / raw)
To: 'gcc@gcc.gnu.org'
I've discovered what I believe to be a bug in the exception unwinding code
of gcc 3.0.3. I wrote a short test function with just a try & catch in a
function, and the unwinder crashes at run time.
I've traced the unwinding through to the call to the C++ personality
function in eh_personality.cc. At the end of the personality function,
_Unwind_SetGR is called to set up a pointer to the exceptionObject
for the call to __cxa_begin_catch later on (eh_personality.cc:393):
_Unwind_SetGR (context, __builtin_eh_return_data_regno (0),
(_Unwind_Ptr) &xh->unwindHeader);
_Unwind_SetGR takes an _Unwind_Word as its third argument.
I'm using a MIPS processor; sizeof(_Unwind_Ptr) is 32 bits, and
sizeof(_Unwind_Word) is 64 bits. _Unwind_Word is an unsigned type
(unwind.h:32):
typedef unsigned _Unwind_Word __attribute__((__mode__(__word__)));
When gcc generates the call to _Unwind_SetGR in the personality
function, it takes the &xh->unwindHeader and zero-extends it
to 64 bits. Later on, the generated code for my "catch" calls
__cxa_begin_catch, and the result of the _Unwind_SetGR is in the
a0 register.
__cxa_begin_catch tries to read a value from the exceptionObject.
The beginning of __cxa_begin_catch looks like this (mips assembly):
__cxa_begin_catch:
addiu sp,sp,-48
sd s0,32(sp)
sd ra,40(sp)
jal __cxa_get_globals
addiu s0,a0,-48
lw v1,20(s0)
So here's the problem: addiu requires its register operand
to be a valid 64-bit sign extended representation of a
32-bit value; if it is not, the result is unpredictable[1].
The zero-extended version that the compiler generates violates
this rule. This problem won't show up with user pointers that
end up < 0x80000000; in kernel mode my pointers are
>= 0x80000000.
It seems that almost all MIPS processors implement addiu as
"do a 32 bit add and then sign extend" so the unpredictable
behaviour produces the expected result.
The processor I'm working with has different unpredictable
behaviour (the result of the addiu still has zeros in bits
63-32), so the "lw" instruction following causes a MIPS
processor exception.
I can probably work around this by casting the
&xh->unwindHeader to a signed word in the personality
function. I'm not sure how this should be properly
fixed, though, as other architectures might have other
issues with such a change.
My compiler info:
Configured with: configure --target=mips-wrs-vxworks --enable-threads
Thread model: vxworks
gcc version 3.0.3
[1]
http://www.mips.com/publications/documentation/MD00087-2B-MIPS64BIS-AFP-00.9
5.pdf, page 39
^ permalink raw reply [flat|nested] 4+ messages in thread
* Exception handling problem on x86-64
@ 2002-04-25 2:55 ` Bo Thorsen
2002-04-25 10:08 ` David Edelsohn
0 siblings, 1 reply; 4+ messages in thread
From: Bo Thorsen @ 2002-04-25 2:55 UTC (permalink / raw)
To: bugs, gcc; +Cc: Jan Hubicka
I'm currently trying to debug why any throw expression in c++ fails.
The reason is that the stackpointer rbp is set to 0xfffffffffffffff8 at some
point which is wrong, but I can't find the place where this happens.
Present leader for the bug is this line (macro expanded):
context->ra = __builtin_extract_return_addr
((void *) (_Unwind_Ptr) _Unwind_GetGR (context, fs->retaddr_column));
at the end of uw_init_context_1 in unwind-dw2.c. It's being called from
_Unwind_RaiseException(struct _Unwind_Exception *exc) in unwind.inc. These
are the first lines in that file:
_Unwind_Reason_Code
_Unwind_RaiseException(struct _Unwind_Exception *exc)
{
struct _Unwind_Context this_context, cur_context;
_Unwind_Reason_Code code;
uw_init_context (&this_context);
cur_context = this_context;
Before the uw_init_context() call, the stack is fine. When it returns, the
stack is corrupted.
Here are the rsp and rbp before and after the calls:
rbp 0x7fbffff420 0x7fbffff420
rsp 0x7fbffff400 0x7fbffff400
...
rbp 0xfffffffffffffff8 0xfffffffffffffff8
rsp 0x7fbffff090 0x7fbffff090
Something sets rbp to a stack offset (at least that's my guess). It seems to
me that the __builtin_extract_return_addr does something quite wrong here.
Unfortunately gdb is quite crippled atm so it's not a great help, but if there
is anything else I can provide to give a further idea of what's going wrong
here, please ask. This bug is driving me nuts.
Here are objdump -drS of the functions:
0000000000447ee0 <uw_update_context_1>:
^L
static void
uw_update_context_1 (struct _Unwind_Context *context, _Unwind_FrameState *fs)
{
447ee0: 41 56 push %r14
struct _Unwind_Context orig_context = *context;
447ee2: b9 19 00 00 00 mov $0x19,%ecx
447ee7: 41 55 push %r13
447ee9: 49 89 fd mov %rdi,%r13
447eec: 41 54 push %r12
447eee: 55 push %rbp
447eef: 48 89 f5 mov %rsi,%rbp
447ef2: 4c 89 ee mov %r13,%rsi
447ef5: 53 push %rbx
447ef6: 48 81 ec e0 00 00 00 sub $0xe0,%rsp
void *cfa;
long i;
/* Compute this frame's CFA. */
switch (fs->cfa_how)
447efd: 8b 85 40 01 00 00 mov 0x140(%rbp),%eax
447f03: 4c 8d 74 24 10 lea 0x10(%rsp,1),%r14
447f08: fc cld
447f09: 83 f8 01 cmp $0x1,%eax
447f0c: 4c 89 f7 mov %r14,%rdi
447f0f: f3 48 a5 repz movsq %ds:(%rsi),%es:(%rdi)
447f12: 0f 84 b6 00 00 00 je 447fce
<uw_update_context_1+0xee>
447f18: 83 f8 02 cmp $0x2,%eax
447f1b: 0f 85 e0 00 00 00 jne 448001
<uw_update_context_1+0x121
>
{
case CFA_REG_OFFSET:
/* Special handling here: Many machines do not use a frame pointer,
and track the CFA only through offsets from the stack pointer from
one frame to the next. In this case, the stack pointer is never
stored, so it has no saved address in the context. What we do
have is the CFA from the previous stack frame. */
if (context->reg[fs->cfa_reg] == NULL)
cfa = context->cfa;
else
cfa = (void *) (_Unwind_Ptr) _Unwind_GetGR (context, fs->cfa_reg);
cfa += fs->cfa_offset;
break;
case CFA_EXP:
/* ??? No way of knowing what register number is the stack pointer
to do the same sort of handling as above. Assume that if the
CFA calculation is so complicated as to require a stack program
that this will not be a problem. */
{
const unsigned char *exp = fs->cfa_exp;
447f21: 48 8b bd 38 01 00 00 mov 0x138(%rbp),%rdi
_Unwind_Word len;
exp = read_uleb128 (exp, &len);
447f28: 48 8d 74 24 08 lea 0x8(%rsp,1),%rsi
447f2d: e8 0e f1 ff ff callq 447040 <read_uleb128>
cfa = (void *) (_Unwind_Ptr)
447f32: 31 c9 xor %ecx,%ecx
447f34: 4c 89 ea mov %r13,%rdx
447f37: 48 89 c6 mov %rax,%rsi
447f3a: 48 89 c7 mov %rax,%rdi
447f3d: 48 03 74 24 08 add 0x8(%rsp,1),%rsi
447f42: e8 e9 f3 ff ff callq 447330 <execute_stack_op>
447f47: 49 89 c4 mov %rax,%r12
execute_stack_op (exp, exp + len, context, 0);
break;
}
default:
abort ();
}
context->cfa = cfa;
447f4a: 4d 89 a5 90 00 00 00 mov %r12,0x90(%r13)
/* Compute the addresses of all registers saved in this frame. */
for (i = 0; i < DWARF_FRAME_REGISTERS + 1; ++i)
447f51: 31 db xor %ebx,%ebx
switch (fs->regs.reg[i].how)
447f53: 48 89 d8 mov %rbx,%rax
447f56: 48 c1 e0 04 shl $0x4,%rax
447f5a: 8b 54 05 08 mov 0x8(%rbp,%rax,1),%edx
447f5e: 83 fa 01 cmp $0x1,%edx
447f61: 74 60 je 447fc3
<uw_update_context_1+0xe3>
447f63: 83 fa 01 cmp $0x1,%edx
447f66: 72 0a jb 447f72
<uw_update_context_1+0x92>
447f68: 83 fa 02 cmp $0x2,%edx
447f6b: 74 4a je 447fb7
<uw_update_context_1+0xd7>
447f6d: 83 fa 03 cmp $0x3,%edx
447f70: 74 19 je 447f8b
<uw_update_context_1+0xab>
447f72: 48 ff c3 inc %rbx
447f75: 48 83 fb 11 cmp $0x11,%rbx
447f79: 7e d8 jle 447f53
<uw_update_context_1+0x73>
{
case REG_UNSAVED:
break;
case REG_SAVED_OFFSET:
context->reg[i] = cfa + fs->regs.reg[i].loc.offset;
break;
case REG_SAVED_REG:
context->reg[i] = orig_context.reg[fs->regs.reg[i].loc.reg];
break;
case REG_SAVED_EXP:
{
const unsigned char *exp = fs->regs.reg[i].loc.exp;
_Unwind_Word len;
_Unwind_Ptr val;
exp = read_uleb128 (exp, &len);
val = execute_stack_op (exp, exp + len, &orig_context,
(_Unwind_Ptr) cfa);
context->reg[i] = (void *) val;
}
break;
}
}
447f7b: 48 81 c4 e0 00 00 00 add $0xe0,%rsp
447f82: 5b pop %rbx
447f83: 5d pop %rbp
447f84: 41 5c pop %r12
447f86: 41 5d pop %r13
447f88: 41 5e pop %r14
447f8a: c3 retq
447f8b: 48 8b 7c 05 00 mov 0x0(%rbp,%rax,1),%rdi
447f90: 48 89 e6 mov %rsp,%rsi
447f93: e8 a8 f0 ff ff callq 447040 <read_uleb128>
447f98: 4c 89 e1 mov %r12,%rcx
447f9b: 4c 89 f2 mov %r14,%rdx
447f9e: 48 89 c6 mov %rax,%rsi
447fa1: 48 89 c7 mov %rax,%rdi
447fa4: 48 03 34 24 add (%rsp,1),%rsi
447fa8: e8 83 f3 ff ff callq 447330 <execute_stack_op>
447fad: 90 nop
447fae: 90 nop
447faf: 90 nop
447fb0: 49 89 44 dd 00 mov %rax,0x0(%r13,%rbx,8)
447fb5: eb bb jmp 447f72
<uw_update_context_1+0x92>
447fb7: 48 8b 44 05 00 mov 0x0(%rbp,%rax,1),%rax
447fbc: 48 8b 44 c4 10 mov 0x10(%rsp,%rax,8),%rax
447fc1: eb ed jmp 447fb0
<uw_update_context_1+0xd0>
447fc3: 48 8b 54 05 00 mov 0x0(%rbp,%rax,1),%rdx
447fc8: 4a 8d 04 22 lea (%rdx,%r12,1),%rax
447fcc: eb e2 jmp 447fb0
<uw_update_context_1+0xd0>
447fce: 48 8b 85 30 01 00 00 mov 0x130(%rbp),%rax
447fd5: 49 83 7c c5 00 00 cmpq $0x0,0x0(%r13,%rax,8)
447fdb: 75 13 jne 447ff0
<uw_update_context_1+0x110
>
447fdd: 4d 8b a5 90 00 00 00 mov 0x90(%r13),%r12
447fe4: 4c 03 a5 28 01 00 00 add 0x128(%rbp),%r12
447feb: e9 5a ff ff ff jmpq 447f4a
<uw_update_context_1+0x6a>
447ff0: 48 63 85 30 01 00 00 movslq 0x130(%rbp),%rax
447ff7: 49 8b 44 c5 00 mov 0x0(%r13,%rax,8),%rax
447ffc: 4c 8b 20 mov (%rax),%r12
447fff: eb e3 jmp 447fe4
<uw_update_context_1+0x104
>
448001: e8 3a 75 00 00 callq 44f540 <abort>
448006: 90 nop
448007: 90 nop
448008: 90 nop
448009: 90 nop
44800a: 90 nop
44800b: 90 nop
44800c: 90 nop
44800d: 90 nop
44800e: 90 nop
44800f: 90 nop
0000000000448010 <uw_update_context>:
static void
uw_update_context (struct _Unwind_Context *context, _Unwind_FrameState *fs)
{
448010: 48 83 ec 18 sub $0x18,%rsp
448014: 4c 89 64 24 10 mov %r12,0x10(%rsp,1)
448019: 48 89 5c 24 08 mov %rbx,0x8(%rsp,1)
44801e: 49 89 f4 mov %rsi,%r12
448021: 48 89 fb mov %rdi,%rbx
uw_update_context_1 (context, fs);
448024: e8 b7 fe ff ff callq 447ee0 <uw_update_context_1>
448029: 49 0f b6 84 24 68 01 movzbq 0x168(%r12,1),%rax
448030: 00 00
/* Compute the return address now, since the return address column
can change from frame to frame. */
context->ra = __builtin_extract_return_addr
((void *) (_Unwind_Ptr) _Unwind_GetGR (context, fs->retaddr_column));
}
448032: 4c 8b 64 24 10 mov 0x10(%rsp,1),%r12
448037: 48 8b 04 c3 mov (%rbx,%rax,8),%rax
44803b: 48 8b 00 mov (%rax),%rax
44803e: 48 89 83 98 00 00 00 mov %rax,0x98(%rbx)
448045: 48 8b 5c 24 08 mov 0x8(%rsp,1),%rbx
44804a: 48 83 c4 18 add $0x18,%rsp
44804e: c3 retq
44804f: 90 nop
44804f: 90 nop
0000000000448050 <uw_init_context_1>:
^L
/* Fill in CONTEXT for top-of-stack. The only valid registers at this
level will be the return address and the CFA. */
#define uw_init_context(CONTEXT) \
do \
{ \
/* Do any necessary initialization to access arbitrary stack frames. \
On the SPARC, this means flushing the register windows. */ \
__builtin_unwind_init (); \
uw_init_context_1 (CONTEXT, __builtin_dwarf_cfa (), \
__builtin_return_address (0)); \
} \
while (0)
static void
uw_init_context_1 (struct _Unwind_Context *context,
void *outer_cfa, void *outer_ra)
{
448050: 48 81 ec a8 01 00 00 sub $0x1a8,%rsp
void *ra = __builtin_extract_return_addr (__builtin_return_address (0));
_Unwind_FrameState fs;
memset (context, 0, sizeof (struct _Unwind_Context));
448057: 31 c0 xor %eax,%eax
448059: 48 89 9c 24 88 01 00 mov %rbx,0x188(%rsp,1)
448060: 00
448061: 48 89 ac 24 90 01 00 mov %rbp,0x190(%rsp,1)
448068: 00
448069: 4c 89 a4 24 98 01 00 mov %r12,0x198(%rsp,1)
448070: 00
448071: 48 8b 9c 24 a8 01 00 mov 0x1a8(%rsp,1),%rbx
448078: 00
448079: 48 89 fd mov %rdi,%rbp
44807c: 4c 89 ac 24 a0 01 00 mov %r13,0x1a0(%rsp,1)
448083: 00
448084: 49 89 f4 mov %rsi,%r12
448087: 49 89 d5 mov %rdx,%r13
44808a: 31 f6 xor %esi,%esi
44808c: ba c8 00 00 00 mov $0xc8,%edx
448091: e8 6a ae 01 00 callq 462f00 <memset>
context->ra = ra;
if (uw_frame_state_for (context, &fs) != _URC_NO_REASON)
448096: 48 89 e6 mov %rsp,%rsi
448099: 48 89 ef mov %rbp,%rdi
44809c: 48 89 9d 98 00 00 00 mov %rbx,0x98(%rbp)
4480a3: e8 68 fa ff ff callq 447b10 <uw_frame_state_for>
4480a8: 85 c0 test %eax,%eax
4480aa: 75 64 jne 448110 <uw_init_context_1+0xc0>
abort ();
/* Force the frame state to use the known cfa value. */
context->cfa = outer_cfa;
4480ac: 4c 89 a5 90 00 00 00 mov %r12,0x90(%rbp)
fs.cfa_how = CFA_REG_OFFSET;
fs.cfa_reg = 0;
fs.cfa_offset = 0;
uw_update_context_1 (context, &fs);
4480b3: 48 89 ef mov %rbp,%rdi
4480b6: 48 89 e6 mov %rsp,%rsi
4480b9: c7 84 24 40 01 00 00 movl $0x1,0x140(%rsp,1)
4480c0: 01 00 00 00
4480c4: 48 c7 84 24 30 01 00 movq $0x0,0x130(%rsp,1)
4480cb: 00 00 00 00 00
4480d0: 48 c7 84 24 28 01 00 movq $0x0,0x128(%rsp,1)
4480d7: 00 00 00 00 00
4480dc: e8 ff fd ff ff callq 447ee0 <uw_update_context_1>
/* If the return address column was saved in a register in the
initialization context, then we can't see it in the given
call frame data. So have the initialization context tell us. */
context->ra = __builtin_extract_return_addr (outer_ra);
4480e1: 4c 89 ad 98 00 00 00 mov %r13,0x98(%rbp)
}
4480e8: 4c 8b ac 24 a0 01 00 mov 0x1a0(%rsp,1),%r13
4480ef: 00
4480f0: 4c 8b a4 24 98 01 00 mov 0x198(%rsp,1),%r12
4480f7: 00
4480f8: 48 8b 9c 24 88 01 00 mov 0x188(%rsp,1),%rbx
4480ff: 00
448100: 48 8b ac 24 90 01 00 mov 0x190(%rsp,1),%rbp
448107: 00
448108: 48 81 c4 a8 01 00 00 add $0x1a8,%rsp
44810f: c3 retq
448110: e8 2b 74 00 00 callq 44f540 <abort>
Bo.
--
Bo Thorsen | Praestevejen 4
Free software developer | 5290 Marslev
SuSE Labs | Denmark
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Exception handling problem on x86-64
2002-04-25 2:55 ` Exception handling problem on x86-64 Bo Thorsen
@ 2002-04-25 10:08 ` David Edelsohn
2002-04-25 10:33 ` Richard Henderson
0 siblings, 1 reply; 4+ messages in thread
From: David Edelsohn @ 2002-04-25 10:08 UTC (permalink / raw)
To: Bo Thorsen; +Cc: bugs, gcc, Jan Hubicka
Is this possibly related to the exception unwinding bug affecting
Mips that Ed Maste reported in February?
http://gcc.gnu.org/ml/gcc/2002-02/msg00532.html
Ed was reporting a sign extension incompatibility.
David
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Exception handling problem on x86-64
2002-04-25 10:08 ` David Edelsohn
@ 2002-04-25 10:33 ` Richard Henderson
0 siblings, 0 replies; 4+ messages in thread
From: Richard Henderson @ 2002-04-25 10:33 UTC (permalink / raw)
To: David Edelsohn; +Cc: Bo Thorsen, bugs, gcc, Jan Hubicka
On Thu, Apr 25, 2002 at 01:07:15PM -0400, David Edelsohn wrote:
> Is this possibly related to the exception unwinding bug affecting
> Mips that Ed Maste reported in February?
No. x86-64 does not have the same 32-bit value in 64-bit
register problem.
r~
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2002-04-25 17:16 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-02-07 8:50 Exception unwinding bug Ed Maste
2002-04-25 2:55 ` Exception handling problem on x86-64 Bo Thorsen
2002-04-25 10:08 ` David Edelsohn
2002-04-25 10:33 ` Richard Henderson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).