This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: x86_64 unwinder in libgcc_s

On 02.08.2012 20:05, Dmitri Shubin wrote:

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 *);

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));

    static _Unwind_Exception static_uex;
    static_uex.exclass = 0x0102030405060708ULL;
    static_uex.excleanup = NULL;

extern void foo(void);

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

        .section .eh_frame,"a",@unwind
        .long .LECIE1-.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

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

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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]