On 02.08.2012 20:05, Dmitri Shubin wrote:
Hello!

I got strange problem in LuaJIT [1] stack unwinding on Solaris x64.

I wrote minimal test that reproduces the problem:

$ cat main.c
#include <stdio.h>
#include <stdint.h>

typedef struct _Unwind_Exception
{
    uint64_t exclass;
    void (*excleanup)(int, struct _Unwind_Exception);
    uintptr_t p1, p2;
} __attribute__((__aligned__)) _Unwind_Exception;

typedef struct _Unwind_Context _Unwind_Context;

extern uintptr_t _Unwind_GetCFA(_Unwind_Context *);
extern int _Unwind_RaiseException(_Unwind_Exception *);

int
foo_personality(int version, int actions, uint64_t uexclass, _Unwind_Exception *uex, _Unwind_Context *ctx)
{
    char *cfa = (char *) _Unwind_GetCFA(ctx);
    printf("cfa = %p\nra = %p\n", cfa, *(void **)(cfa - 8));
}

void
throw()
{
    static _Unwind_Exception static_uex;
    static_uex.exclass = 0x0102030405060708ULL;
    static_uex.excleanup = NULL;
    _Unwind_RaiseException(&static_uex);
}

extern void foo(void);

int
main()
{
    printf("&main = %p, &foo = %p\n", &main, &foo);
    foo();
    return 0;
}
$ cat foo.s
        .file   "foo.s"
        .text
.globl foo
        .type   foo, @function
foo:
        call    throw
        ret
        .size   foo, .-foo

        .section .eh_frame,"a",@unwind
.Lframe1:
        .long .LECIE1-.LSCIE1
.LSCIE1:
        .long 0
        .byte 0x1
        .string "zPR"
        .uleb128 0x1
        .sleb128 -8
        .byte 0x10
        .uleb128 6
        .byte 0x1b
        .long foo_personality-.
        .byte 0x1b
        .byte 0xc
        .uleb128 0x7
        .uleb128 8
        .byte 0x80+0x10
        .uleb128 0x1
        .align 8
.LECIE1:

.LSFDE2:
        .long .LEFDE2-.LASFDE2
.LASFDE2:
        .long .LASFDE2-.Lframe1
        .long foo-.
        .long 6
        .uleb128 0
        .align 8
.LEFDE2:

First I use GCC (4.7.1 from OpenCSW) to compile both files:

$ /opt/csw/bin/gcc --version | head -1
gcc (GCC) 4.7.1
$ /opt/csw/bin/gcc -m64 main.c foo.s
$ ./a.out
&main = 401834, &foo = 401860
cfa = fffffd7fffdffaf8
ra = 401865
$ gobjdump -dr a.out
...
0000000000401860 <foo>:
  401860:       e8 a0 ff ff ff          callq  401805 <throw>
  401865:       c3                      retq
        ...

AFAIU here GCC supplied stack unwinder from statically linked libgcc_s is used and return address for foo context points to somewhere inside foo()

Second I use GCC (gas in fact) to compile foo.s and SunStudio C to compile main.c and link:
$ cc -V 2>&1 | head -1
cc: Sun C 5.11 SunOS_i386 145355-03 2011/02/11
$ /opt/csw/bin/gcc -m64 -c foo.s
$ cc -m64 main.c foo.o
$ ./a.out
&main = 400b30, &foo = 400b70
cfa = fffffd7fffdffaf0
ra = 400b61
$ gobjdump -dr a.out
...
0000000000400b30 <main>:
  400b30:       55                      push   %rbp
  400b31:       48 8b ec                mov    %rsp,%rbp
  400b34:       48 83 ec 10             sub    $0x10,%rsp
  400b38:       48 c7 c2 70 0b 40 00    mov    $0x400b70,%rdx
  400b3f:       48 c7 c6 30 0b 40 00    mov    $0x400b30,%rsi
  400b46:       48 c7 c7 e0 0b 40 00    mov    $0x400be0,%rdi
  400b4d:       b8 00 00 00 00          mov    $0x0,%eax
  400b52:       e8 49 fd ff ff          callq  4008a0 <printf@plt>
  400b57:       b8 00 00 00 00          mov    $0x0,%eax
  400b5c:       e8 0f 00 00 00          callq  400b70 <foo>
  400b61:       c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
  400b68:       8b 45 fc                mov    -0x4(%rbp),%eax
  400b6b:       c9                      leaveq
  400b6c:       c3                      retq
  400b6d:       00 00                   add    %al,(%rax)
        ...

In this case standard Solaris unwinder from libc is used and return address points to main()

From my understanding of CFA definition given in x86-64 psABI ("the value of %rsp at the call site in the previous frame." 6.2.5 Context Management) it looks like value returned by GCC unwinder is wrong.
Am I missing something here?

BTW on Linux (w/ GCC) RA points to foo() as in case 1 so it's GCC-specific rather than Solaris-specific behavior.

Thanks!

Reply via email to