x86_64 unwinder in libgcc_s

2012-08-02 Thread Dmitri Shubin

Hello!

I got strange problem in LuaJIT [1] stack unwinding on Solaris x64.
If I build everything using GCC with unwinder from libgcc_s everything 
works fine.
But when I try to use GCC-built libluajit.a in executable built using 
Sun Studio 12.2 with standard solaris unwinder from libc I got a crash.


As it turned out this is due to invalid value that _Unwind_GetCFA() 
function returned (called from Lua personality routine)


E.g. in core I can see the following stack:

  [1] err_unwind(0x71255e31, 0x6e0bd80, 0x0, 0x6e0bd80, 0x6e0b5d0, 
0x7124bbb5), at 0x7124b875

  [2] lj_err_unwind_dwarf(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 0x7124bc25
  [3] _Unwind_RaiseException_Body(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 
0xfd7ffaae0bfc
  [4] _SUNW_Unwind_RaiseException(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 
0xfd7ffaae0de9

  [5] err_raise_ext(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 0x7124be2c
  [6] lj_err_throw(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 0x7124be89
  [7] lj_trace_err_info(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 0x7129b8d8
  [8] lj_record_ins(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 0x7127f0ec
  [9] trace_state(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 0x7129d7cd
  [10] lj_vm_cpcall(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 0x712473ba
  [11] lj_trace_ins(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 0x7129db8d
  [12] lj_dispatch_ins(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 0x71255e31
  [13] lj_vm_inshook(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 0x71248a41
  [14] lua_pcall(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 0x7125a584
...

lj_err_unwind_dwarf() is personality routine for lj_vm_cpcall()  (frame 
10) so it's called to process its stack frame.


x86_64 psABI says that _Unwind_GetCFA() "returns the 64-bit Canonical 
Frame Address which is defined as
the value of %rsp at the call site in the previous frame." (6.2.5 
Context Management)


So if I understand this correctly *(CFA - 8) should contain address 
somewhere inside lj_vm_cpcall() caller, i.e. in lj_trace_ins() (frame 11).

And when using Solaris std unwinder it's in fact true, but it crashes.
When using GCC unwinder return address is somewhere inside 
lj_vm_cpcall() itself, i.e. AFAIU CFA for trace_state() (frame 9) is 
returned instead, but it works.


I can make std unwinder work by adjusting returned CFA to point to next 
frame by subtracting 80 bytes from it but it's interesting to understand 
why this happens.


Am I missing something and GCC unwinder is right?

TIA

[1] http://luajit.org/


Re: x86_64 unwinder in libgcc_s

2012-08-06 Thread Dmitri Shubin

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 
#include 

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:
callthrow
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 = fd7fffdffaf8
ra = 401865
$ gobjdump -dr a.out
...
00401860 :
  401860:   e8 a0 ff ff ff  callq  401805 
  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 = fd7fffdffaf0
ra = 400b61
$ gobjdump -dr a.out
...
00400b30 :
  400b30:   55  push   %rbp
  400b31:   48 8b ecmov%rsp,%rbp
  400b34:   48 83 ec 10 sub$0x10,%rsp
  400b38:   48 c7 c2 70 0b 40 00mov$0x400b70,%rdx
  400b3f:   48 c7 c6 30 0b 40 00mov$0x400b30,%rsi
  400b46:   48 c7 c7 e0 0b 40 00mov$0x400be0,%rdi
  400b4d:   b8 00 00 00 00  mov$0x0,%eax
  400b52:   e8 49 fd ff ff  callq  4008a0 
  400b57:   b8 00 00 00 00  mov$0x0,%eax
  400b5c:   e8 0f 00 00 00  callq  400b70 
  400b61:   c7 45 fc 00 00 00 00movl   $0x0,-0x4(%rbp)
  400b68:   8b 45 fcmov-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!


Re: x86_64 unwinder in libgcc_s

2012-08-07 Thread Dmitri Shubin

On 06.08.2012 21:13, Richard Henderson wrote:

On 08/06/2012 08:23 AM, Dmitri Shubin wrote:

 char *cfa = (char *) _Unwind_GetCFA(ctx);
 printf("cfa = %p\nra = %p\n", cfa, *(void **)(cfa - 8));

Use _Unwind_GetIP here, for one.
In fact I'm not interested in IP or RA here, I need some context stored 
by assembly routine on the stack relative to its CFA.
I use RA only to illustrate that I got "wrong" (from my pov) CFA from 
libgcc unwinder.
And the question is is it a bug (or deviation from x86-64 psABI) in 
libgcc or I misunderstand what CFA is.


Re: x86_64 unwinder in libgcc_s

2012-08-14 Thread Dmitri Shubin

Any thoughts on this?
Or maybe it's wrong list for this question?

On 07.08.2012 12:09, Dmitri Shubin wrote:

On 06.08.2012 21:13, Richard Henderson wrote:

On 08/06/2012 08:23 AM, Dmitri Shubin wrote:

 char *cfa = (char *) _Unwind_GetCFA(ctx);
 printf("cfa = %p\nra = %p\n", cfa, *(void **)(cfa - 8));

Use _Unwind_GetIP here, for one.
In fact I'm not interested in IP or RA here, I need some context 
stored by assembly routine on the stack relative to its CFA.
I use RA only to illustrate that I got "wrong" (from my pov) CFA from 
libgcc unwinder.
And the question is is it a bug (or deviation from x86-64 psABI) in 
libgcc or I misunderstand what CFA is.




Re: x86_64 unwinder in libgcc_s

2012-08-14 Thread Dmitri Shubin

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 
#include 

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
callthrow
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 = fd7fffdffb10
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 = fd7fffdffb10
ra = 4018a4
ip = 4018a4
v = fd7fffdffb20
*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


Re: x86_64 unwinder in libgcc_s

2012-08-16 Thread Dmitri Shubin

On 14.08.2012 17:58, Ian Lance Taylor wrote:

unwinder is right and libgcc_s one is wrong.
I think the definition of _Unwind_GetCFA is ambiguous.  It says "the
value of %rsp at the call site in the previous frame."  GCC is
returning the value of %rsp at the point of the call to throw.
Solaris is returning the value of %rsp at the call to foo.  I don't
know which is correct.  _Unwind_GetCFA is not part of the C++
exception handling ABI; I'm not sure where it came from.
_Unwind_GetCFA() is defined in x86_64 psABI: 
www.*x86*-*64*.org/documentation/*abi*.pdf

"6.2 Unwind Library Interface"

In my example foo_personality() is set as personality routine for foo() 
so I assume the former is called with _Unwind_Context created for foo()
I.e. foo()'s stack frame is 'current' and from this pov the value of 
'previous frame' is unambiguous -- it's main()'s frame.


BTW dwarf unwinding instructions generated by GCC use CFA-relative 
addresses to locate registers saved on stack frame:


$ cat a.c
void foo()
{
}
$ /opt/csw/bin/gcc -m64 -c a.c
$ gobjdump -dr a.o

a.o: file format elf64-x86-64-sol2


Disassembly of section .text:

 :
   0:   55  push   %rbp
   1:   48 89 e5mov%rsp,%rbp
   4:   5d  pop%rbp
   5:   c3  retq
$ gobjdump -Wf a.o

a.o: file format elf64-x86-64-sol2

Contents of the .eh_frame section:

 0014  CIE
  Version:   1
  Augmentation:  "zR"
  Code alignment factor: 1
  Data alignment factor: -8
  Return address column: 16
  Augmentation data: 1b

  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_offset: r16 (rip) at cfa-8
  DW_CFA_nop
  DW_CFA_nop

0018 001c 001c FDE cie= pc=..0006
  DW_CFA_advance_loc: 1 to 0001
  DW_CFA_def_cfa_offset: 16
  DW_CFA_offset: r6 (rbp) at cfa-16
  DW_CFA_advance_loc: 3 to 0004
  DW_CFA_def_cfa_register: r6 (rbp)
  DW_CFA_advance_loc: 1 to 0005
  DW_CFA_def_cfa: r7 (rsp) ofs 8
  DW_CFA_nop
  DW_CFA_nop
  DW_CFA_nop

Here CIE specifies that right before executing first instruction of 
foo() CFA is RSP+8 and return address is stored at offset -8 from CFA.



Why do you want the CFA?  Perhaps you can use _Unwind_GetGR or other
functions that are part of the C++ exception interface?



It's not me, it's author of LuaJIT who use CFA to get some state 
information from stack frame.

Here is his reply to my question about unwinding problem on Solaris x64
http://www.freelists.org/post/luajit/Stack-unwinding-problem-on-Solaris-x64,1