On 14.08.2012 14:18, Andrew Haley wrote:
You've already had an answer from Richard Henderson, who is probably the best-placed person to answer you.

My question was: why I get wrong (from my pov) CFA value from GCC unwinder.

I rewritten my small test.

$ 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 uintptr_t _Unwind_GetIP(_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);
    char *ip = (char *) _Unwind_GetIP(ctx);
    uint64_t v = *(uint64_t *)(cfa - 16);
printf("cfa = %p\nra = %p\nip = %p\nv = %llx\n*cfa = %llx\n", cfa, *(void **)(cfa - 8), ip, v, *(uint64_t *)cfa);
    return 8;   // _URC_CONTINUE_UNWIND
}

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:
        mov     $0x1020304050,%rax
        push    %rax
        call    throw
        pop     %rax
        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 17
        .uleb128 0
        .byte 0xe
        .uleb128 16
        .align 8
.LEFDE2:

As one can see here in foo() I placed constant 0x1020304050 right after return address to main(), e.g. *(CFA - 16) and in personality routine I try to get it from there.
First I use standard Solaris unwinder from libc:

$ /opt/csw/bin/gas -64 foo.s
$ cc -m64 main.c foo.o
$ ./a.out
&main = 400bc0, &foo = 400c00
cfa = fffffd7fffdffb10
ra = 400bf1
ip = 400c10
v = 1020304050
*cfa = 1

And got expected value (v = 1020304050).

Then I use unwinder from libgcc_s:

$ /opt/csw/bin/gcc -m64 main.c foo.s
$ ./a.out
&main = 40186a, &foo = 401894
cfa = fffffd7fffdffb10
ra = 4018a4
ip = 4018a4
v = fffffd7fffdffb20
*cfa = 1020304050

And got something totally wrong.

In foo_personality() I expect to have the following stack layout for foo() frame (width is 8 bytes):

:                :                                                  ^
| main() frame   |                                                  |
+----------------+ <--- CFA for foo() | increasing addresses
| return address | <--- points to somewhere in main()               |
+----------------+                                                  |
| 0x1020304050   | <--- some context value stored by foo()          |
+----------------+
:                :

And this is what I have when using Solaris unwinder. But libgcc returned me another CFA:

:                :                                                  ^
| main() frame   |                                                  |
+----------------+                               | increasing addresses
| return address | <--- points to somewhere in main()               |
+----------------+                                                  |
| 0x1020304050   | <--- some context value stored by foo()          |
+----------------+ <--- CFA for foo() returned by libgcc_s
:                :

So the question is who is right here?
From my understanding of definition of CFA given in x86_64 psABI Solaris unwinder is right and libgcc_s one is wrong.

See also http://stackoverflow.com/questions/7534420/gas-explanation-of-cfi-def-cfa-offset

Reply via email to