http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50678

--- Comment #35 from Eric Botcazou <ebotcazou at gcc dot gnu.org> 2011-10-17 
15:36:11 UTC ---
> 1. the code for the D10 libSystem unwind library is available from here:
> http://www.opensource.apple.com/tarballs/libunwind/

Thanks for the pointer.

> 2. Looking at a build of this, the order of the assignments (R newRegisters =
> register) seems generally scrambled when the getCFA function is inlined.  This
> is reproducible with the vendor's tools and the source in 1 at optimization
> levels > 0 and not Os.
> 
> 3. The scrambling is consistent (in and out) - and I'm not 100% sure about
> whether this is the fault... ISTM that so long as the re-ordering is local
> (and consistent) to optimized code, it could be harmless.

It wasn't so much the order of assignments as the difference in the offsets
between the contexts.  But, you're right, this isn't the problem as the local
variable newRegisters is very likely scalarized, so the final offsets are
entirely meaningless.  In any case, the problem is elsewhere, namely in the
unwind info for the _sigtramp function of the libc:

(gdb) b *0x00007fff85b9b1b8
Breakpoint 1 at 0x7fff85b9b1b8
(gdb) run
Starting program: /nfs/nas/homes/botcazou/c52104y_0
     C52104Y CHECK THAT IN ARRAY ASSIGNMENTS AND IN SLICE ASSIGNMENTS,
                THE LENGTHS MUST MATCH.
   - C52104Y NO CONSTRAINT_ERROR FOR NON-NULL ARRAY SUBTYPE WHEN ONE
                DIMENSION HAS INTEGER'LAST + 3 COMPONENTS.

Program received signal SIGSEGV, Segmentation fault.
0x0000000100002428 in c52104y_0 ()
(gdb) continue
Continuing.

Breakpoint 1, <signal handler called>
(gdb) disass
Dump of assembler code for function _sigtramp:
   0x00007fff85b9b1a0 <+0>:     push   %rbp
   0x00007fff85b9b1a1 <+1>:     mov    %rsp,%rbp
   0x00007fff85b9b1a4 <+4>:     mov    %rdi,%rax
   0x00007fff85b9b1a7 <+7>:     incl   -0x15261b75(%rip)        #
0x7fff70939638
   0x00007fff85b9b1ad <+13>:    mov    %r8,%rbx
   0x00007fff85b9b1b0 <+16>:    mov    %edx,%edi
   0x00007fff85b9b1b2 <+18>:    mov    %rcx,%rsi
   0x00007fff85b9b1b5 <+21>:    mov    %r8,%rdx
=> 0x00007fff85b9b1b8 <+24>:    callq  *%rax
   0x00007fff85b9b1ba <+26>:    decl   -0x15261b88(%rip)        #
0x7fff70939638
   0x00007fff85b9b1c0 <+32>:    mov    %rbx,%rdi
   0x00007fff85b9b1c3 <+35>:    mov    $0x1e,%esi
   0x00007fff85b9b1c8 <+40>:    jmpq   0x7fff85b9b1d0 <__sigreturn>
   0x00007fff85b9b1cd <+45>:    nop
   0x00007fff85b9b1ce <+46>:    nop
   0x00007fff85b9b1cf <+47>:    nop
End of assembler dump.

The CFI of the unwind info for _sigtramp is at this address:

(gdb) x/167bx 0x00007fff85ccff59
0x7fff85ccff59: 0x10    0x00    0x05    0x73    0x30    0x06    0x23    0x10
0x7fff85ccff61: 0x10    0x01    0x05    0x73    0x30    0x06    0x23    0x18
0x7fff85ccff69: 0x10    0x02    0x05    0x73    0x30    0x06    0x23    0x20
0x7fff85ccff71: 0x10    0x03    0x05    0x73    0x30    0x06    0x23    0x28
0x7fff85ccff79: 0x10    0x04    0x05    0x73    0x30    0x06    0x23    0x38
0x7fff85ccff81: 0x10    0x05    0x05    0x73    0x30    0x06    0x23    0x30
0x7fff85ccff89: 0x10    0x06    0x05    0x73    0x30    0x06    0x23    0x40
0x7fff85ccff91: 0x10    0x07    0x05    0x73    0x30    0x06    0x23    0x48
0x7fff85ccff99: 0x10    0x08    0x05    0x73    0x30    0x06    0x23    0x50
0x7fff85ccffa1: 0x10    0x09    0x05    0x73    0x30    0x06    0x23    0x58
0x7fff85ccffa9: 0x10    0x0a    0x05    0x73    0x30    0x06    0x23    0x60
0x7fff85ccffb1: 0x10    0x0b    0x05    0x73    0x30    0x06    0x23    0x68
0x7fff85ccffb9: 0x10    0x0c    0x05    0x73    0x30    0x06    0x23    0x70
0x7fff85ccffc1: 0x10    0x0d    0x05    0x73    0x30    0x06    0x23    0x78
0x7fff85ccffc9: 0x10    0x0e    0x06    0x73    0x30    0x06    0x23    0x80

DW_CFA_expression reg_num len DW_OP_breg3 off deref DW_OP_plus_uconst offset

So, for example, register 1 is at offset 0x18 of the deref of (%rdx + 0x30):

(gdb) x/gx ($rdx + 0x30)
0x100038958:    0x00000001000384bc

(gdb) x/gx 0x00000001000384bc + 0x18
0x1000384d4:    0x00007fff5fbff910

And register 3 is at offset 0x18 of the deref of (%rdx + 0x30):

(gdb) x/gx 0x00000001000384bc + 0x28
0x1000384e4:    0x0000000010000000

The former is the saved %rbx and the latter is the saved %rdx.  The problem is
that they are numbered differently by libunwind.h:

// 64-bit x86_64 registers
enum {
    UNW_X86_64_RAX =  0,
    UNW_X86_64_RDX =  1,
    UNW_X86_64_RCX =  2,
    UNW_X86_64_RBX =  3,
    UNW_X86_64_RSI =  4,
    UNW_X86_64_RDI =  5,
    UNW_X86_64_RBP =  6,
    UNW_X86_64_RSP =  7,
    UNW_X86_64_R8  =  8,
    UNW_X86_64_R9  =  9,
    UNW_X86_64_R10 = 10,
    UNW_X86_64_R11 = 11,
    UNW_X86_64_R12 = 12,
    UNW_X86_64_R13 = 13,
    UNW_X86_64_R14 = 14,
    UNW_X86_64_R15 = 15
};

so %rbx is register 3 and %rdx is register 1 for libunwind.  Therefore, if you
swap the saved values, the program works fine:

(gdb) set { unsigned long } 0x1000384d4 = 0x0000000010000000
(gdb) set { unsigned long } 0x1000384e4 = 0x00007fff5fbff910
(gdb) continue
Continuing.
   - C52104Y STORAGE_ERROR RAISED WHEN DECLARING ONE PACKED BOOLEAN
                ARRAY WITH INTEGER'LAST + 3 COMPONENTS.
==== C52104Y PASSED ============================.



The unwind info for _sigtramp is in i386/sys/_sigtramp.s for i386:

    /* Now for the expressions, which all compute
       uctx->uc_mcontext->register
       for each register.

       Describe even the registers that are not call-saved because they
       might be being used in the prologue to save other registers.
       Only integer registers are described at present.    */

    loc_expr_for_reg (0, MCONTEXT_SS_EAX)
    loc_expr_for_reg (1, MCONTEXT_SS_ECX)
    loc_expr_for_reg (2, MCONTEXT_SS_EDX)
    loc_expr_for_reg (3, MCONTEXT_SS_EBX)
    loc_expr_for_reg (4, MCONTEXT_SS_EBP) # note that GCC switches
    loc_expr_for_reg (5, MCONTEXT_SS_ESP) # DWARF registers 4 & 5
    loc_expr_for_reg (6, MCONTEXT_SS_ESI)
    loc_expr_for_reg (7, MCONTEXT_SS_EDI)
    loc_expr_for_reg (9, MCONTEXT_SS_EFLAGS)

It is in keeping with libunwind.h:

// 32-bit x86 registers
enum {
    UNW_X86_EAX = 0,
    UNW_X86_ECX = 1,
    UNW_X86_EDX = 2,
    UNW_X86_EBX = 3,
    UNW_X86_EBP = 4,
    UNW_X86_ESP = 5,
    UNW_X86_ESI = 6,
    UNW_X86_EDI = 7
};


The unwind info for _sigtramp is in x86_64/sys/_sigtramp.s for x86-64:

    /* Now for the expressions, which all compute
       uctx->uc_mcontext->register
       for each register.

       Describe even the registers that are not call-saved because they
       might be being used in the prologue to save other registers.
       Only integer registers are described at present.    */

    loc_expr_for_reg (0, MCONTEXT_SS_RAX)
    loc_expr_for_reg (1, MCONTEXT_SS_RBX)
    loc_expr_for_reg (2, MCONTEXT_SS_RCX)
    loc_expr_for_reg (3, MCONTEXT_SS_RDX)
    loc_expr_for_reg (4, MCONTEXT_SS_RSI)
    loc_expr_for_reg (5, MCONTEXT_SS_RDI)
    loc_expr_for_reg (6, MCONTEXT_SS_RBP)
    loc_expr_for_reg (7, MCONTEXT_SS_RSP)
    loc_expr_rN (8)
    loc_expr_rN (9)
    loc_expr_rN (10)
    loc_expr_rN (11)
    loc_expr_rN (12)
    loc_expr_rN (13)
    loc_expr_rN_long (14)
    loc_expr_rN_long (15)

and it is _not_ in keeping with libunwind.h:

// 64-bit x86_64 registers
enum {
    UNW_X86_64_RAX =  0,
    UNW_X86_64_RDX =  1,
    UNW_X86_64_RCX =  2,
    UNW_X86_64_RBX =  3,
    UNW_X86_64_RSI =  4,
    UNW_X86_64_RDI =  5,
    UNW_X86_64_RBP =  6,
    UNW_X86_64_RSP =  7,
    UNW_X86_64_R8  =  8,
    UNW_X86_64_R9  =  9,
    UNW_X86_64_R10 = 10,
    UNW_X86_64_R11 = 11,
    UNW_X86_64_R12 = 12,
    UNW_X86_64_R13 = 13,
    UNW_X86_64_R14 = 14,
    UNW_X86_64_R15 = 15
};

The discrepancy in the x86-64 case is the bug.


This should be reported to Apple and probably fixed in the libc.  In the
meantime, we can work around it in ada/init.c/__gnat_error_handler:

static void
__gnat_error_handler (int sig, siginfo_t *si, void *ucontext ATTRIBUTE_UNUSED)
{

by patching up the context reachable through the ucontext argument.  According
to the comment in the libc file, it is at ucontext->uc_mcontext.

Reply via email to