void
s390_emit_tpf_eh_return (rtx target)
{
- rtx insn, reg;
+ rtx insn, reg, orig_ra;
if (!s390_tpf_eh_return_symbol)
s390_tpf_eh_return_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tpf_eh_return");
reg = gen_rtx_REG (Pmode, 2);
+ orig_ra = gen_rtx_REG (Pmode, 3);
emit_move_insn (reg, target);
+ emit_move_insn (orig_ra, get_hard_reg_initial_val (Pmode, RETURN_REGNUM));
insn = s390_emit_call (s390_tpf_eh_return_symbol, NULL_RTX, reg,
gen_rtx_REG (Pmode, RETURN_REGNUM));
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), reg);
+ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), orig_ra);
emit_move_insn (EH_RETURN_HANDLER_RTX, reg);
}
<http://www.gnu.org/licenses/>. */
#include <dlfcn.h>
+#include <stdbool.h>
/* Function Name: __isPATrange
Parameters passed into it: address to check
#define TPFAREA_SIZE STACK_POINTER_OFFSET-TPFAREA_OFFSET
#define INVALID_RETURN 0
-void * __tpf_eh_return (void *target);
+void * __tpf_eh_return (void *target, void *origRA);
void *
-__tpf_eh_return (void *target)
+__tpf_eh_return (void *target, void *origRA)
{
Dl_info targetcodeInfo, currentcodeInfo;
int retval;
void *current, *stackptr, *destination_frame;
- unsigned long int shifter, is_a_stub;
+ unsigned long int shifter;
+ bool is_a_stub, frameDepth2, firstIteration;
- is_a_stub = 0;
+ is_a_stub = false;
+ frameDepth2 = false;
+ firstIteration = true;
/* Get code info for target return's address. */
retval = dladdr (target, &targetcodeInfo);
+ /* Check if original RA is a Pat stub. If so set flag. */
+ if (__isPATrange (origRA))
+ frameDepth2 = true;
+
/* Ensure the code info is valid (for target). */
if (retval != INVALID_RETURN)
{
-
- /* Get the stack pointer of the stack frame to be modified by
- the exception unwinder. So that we can begin our climb
- there. */
- stackptr = (void *) *((unsigned long int *) (*(PREVIOUS_STACK_PTR())));
+ /* Get the stack pointer of the first stack frame beyond the
+ unwinder or if exists the calling C++ runtime function (e.g.,
+ __cxa_throw). */
+ if (!frameDepth2)
+ stackptr = (void *) *((unsigned long int *) (*(PREVIOUS_STACK_PTR())));
+ else
+ stackptr = (void *) *(PREVIOUS_STACK_PTR());
/* Begin looping through stack frames. Stop if invalid
code information is retrieved or if a match between the
matches that of the target, calculated above. */
do
{
- /* Get return address based on our stackptr iterator. */
- current = (void *) *((unsigned long int *)
- (stackptr+RA_OFFSET));
-
- /* Is it a Pat Stub? */
- if (__isPATrange (current))
+ if (!frameDepth2 || (frameDepth2 && !firstIteration))
+ {
+ /* Get return address based on our stackptr iterator. */
+ current = (void *) *((unsigned long int *)
+ (stackptr + RA_OFFSET));
+
+ /* Is it a Pat Stub? */
+ if (__isPATrange (current))
+ {
+ /* Yes it was, get real return address in TPF stack area. */
+ current = (void *) *((unsigned long int *)
+ (stackptr + TPFRA_OFFSET))
+ is_a_stub = true;
+ }
+ }
+ else
{
- /* Yes it was, get real return address
- in TPF stack area. */
current = (void *) *((unsigned long int *)
- (stackptr+TPFRA_OFFSET));
- is_a_stub = 1;
+ (stackptr + TPFRA_OFFSET));
+ is_a_stub = true;
}
/* Get codeinfo on RA so that we can figure out
This is necessary for CTOA stubs.
Otherwise we leap one byte past where we want to
go to in the TPF pat stub linkage code. */
- shifter = *((unsigned long int *)
- (stackptr + RA_OFFSET));
+ if (!frameDepth2 || (frameDepth2 && !firstIteration))
+ shifter = *((unsigned long int *) (stackptr + RA_OFFSET));
+ else
+ shifter = (unsigned long int) origRA;
shifter &= ~1ul;
Bump stack frame iterator. */
stackptr = (void *) *(unsigned long int *) stackptr;
- is_a_stub = 0;
+ is_a_stub = false;
+ firstIteration = false;
} while (stackptr && retval != INVALID_RETURN
&& targetcodeInfo.dli_fbase != currentcodeInfo.dli_fbase);