x86_64 unwinder in libgcc_s

Dmitri Shubin sbn@tbricks.com
Thu Aug 2 16:06:00 GMT 2012


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 
0xfffffd7ffaae0bfc
   [4] _SUNW_Unwind_RaiseException(0x0, 0x0, 0x0, 0x0, 0x0, 0x0), at 
0xfffffd7ffaae0de9
   [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/



More information about the Gcc mailing list