[PATCH] Fix ffi powerpc64 unwind info
Jakub Jelinek
jakub@redhat.com
Fri Nov 24 22:18:00 GMT 2006
Hi!
When libgcj.so is linked with an anonymous version script which hides all
the symbols which aren't part of the libgcj.so ABI (e.g. GC_*, ffi_*, fdlibm
symbols, etc.; will post such a patch soon), invokethrow test fails on
ppc64. The reason for this is no explicit unwind info for the r2 (TOC)
register. ffi_call_LINUX64 explicitely saves this register, but doesn't
mention that in the unwind info. Unwinding on ppc64 implicitly
adds a rule to restore r2 if the instruction at RA is ld %r2, 40(%r1)
(that's what the linker replaces nops after bl instructions with it
it calls something which (maybe) needs a different TOC pointer.
When ffi_call symbol is exported out of libgcj.so, unwinding sort of works
fine, eventhough %r2 in ffi_call_LINUX64 and ffi_call is wrong, there are no
catch regions in those and as all calls to ffi_call in that case are
followed by ld %r2, 40(%r1), TOC register is correctly unwinded at least
in ffi_call caller and above. But when ffi_call is hidden within
libgcj.so (and ffi_call_LINUX64 is hidden there too, which is the case for
several years no), r2 will be wrong even in ffi_call caller when unwinding
and as _Jv_Throw has try { ffi_call (...); } catch (...) { ... } construct
around it, invokethrow test crashes.
Attached are two possible fixes, one doesn't chance the code at all,
just adds CFA expression where r2 is saved, the other moves ld %r2, 40(%r1)
instruction around to force the implicit unwinder behavior.
Ok for head? Which one?
Jakub
-------------- next part --------------
2006-11-24 Jakub Jelinek <jakub@redhat.com>
* src/powerpc/linux64.S (ffi_call_LINUX64): Add DW_CFA_expression
for r2.
--- libffi/src/powerpc/linux64.S.jj 2006-08-02 20:55:10.000000000 +0200
+++ libffi/src/powerpc/linux64.S 2006-11-24 21:38:16.000000000 +0100
@@ -47,12 +47,13 @@ ffi_call_LINUX64:
std %r0, 16(%r1)
mr %r28, %r1 /* our AP. */
- stdux %r1, %r1, %r4
.LCFI0:
+ stdux %r1, %r1, %r4
mr %r31, %r5 /* flags, */
mr %r30, %r6 /* rvalue, */
mr %r29, %r7 /* function address. */
std %r2, 40(%r1)
+.LCFI1:
/* Call ffi_prep_args64. */
mr %r4, %r1
@@ -159,8 +160,6 @@ ffi_call_LINUX64:
.uleb128 0x0 # Augmentation size
.byte 0x2 # DW_CFA_advance_loc1
.byte .LCFI0-.LFB1
- .byte 0xd # DW_CFA_def_cfa_register
- .uleb128 0x1c
.byte 0x11 # DW_CFA_offset_extended_sf
.uleb128 0x41
.sleb128 -2
@@ -172,7 +171,16 @@ ffi_call_LINUX64:
.uleb128 0x3
.byte 0x9c # DW_CFA_offset, column 0x1c
.uleb128 0x4
- .align 3
+ .byte 0xd # DW_CFA_def_cfa_register
+ .uleb128 0x1c
+ .byte 0x2 # DW_CFA_advance_loc1
+ .byte .LCFI1-.LCFI0
+ .byte 0x10 # DW_CFA_expression
+ .uleb128 0x2
+ .uleb128 2f-1f
+1: .byte 0x71 # DW_OP_breg1
+ .sleb128 40
+2: .align 3
.LEFDE1:
#endif
-------------- next part --------------
2006-11-24 Jakub Jelinek <jakub@redhat.com>
* src/powerpc/linux64.S (ffi_call_LINUX64): Move restore of r2
immediately after bctrl instruction.
--- libffi/src/powerpc/linux64.S.jj 2006-08-02 20:55:10.000000000 +0200
+++ libffi/src/powerpc/linux64.S 2006-11-24 21:57:06.000000000 +0100
@@ -47,8 +47,8 @@ ffi_call_LINUX64:
std %r0, 16(%r1)
mr %r28, %r1 /* our AP. */
- stdux %r1, %r1, %r4
.LCFI0:
+ stdux %r1, %r1, %r4
mr %r31, %r5 /* flags, */
mr %r30, %r6 /* rvalue, */
mr %r29, %r7 /* function address. */
@@ -100,6 +100,10 @@ ffi_call_LINUX64:
/* Make the call. */
bctrl
+ /* This must follow the call immediately, the unwinder
+ uses this to find out if r2 has been saved or not. */
+ ld %r2, 40(%r1)
+
/* Now, deal with the return value. */
mtcrf 0x01, %r31
bt- 30, .Ldone_return_value
@@ -109,7 +113,6 @@ ffi_call_LINUX64:
.Ldone_return_value:
/* Restore the registers we used and return. */
- ld %r2, 40(%r1)
mr %r1, %r28
ld %r0, 16(%r28)
ld %r28, -32(%r1)
More information about the Gcc-patches
mailing list