public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* 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).