S/390 zTPF: Handle skip trace addresses when unwinding
Check for and handle new skip trace addresses when unwinding on zTPF. libgcc/ChangeLog: 2020-04-03 Jim Johnston <jjohnst@us.ibm.com> * config/s390/tpf-unwind.h (MIN_PATRANGE, MAX_PATRANGE) (TPFRA_OFFSET): Macros removed. (CP_CNF, cinfc_fast, CINFC_CMRESET, CINTFC_CMCENBKST) (CINTFC_CMCENBKED, ICST_CRET, ICST_SRET, LOWCORE_PAGE3_ADDR) (PG3_SKIPPING_OFFSET): New macros. (__isPATrange): Use cinfc_fast for the check. (__isSkipResetAddr): New function. (s390_fallback_frame_state): Check for skip trace addresses. Use either ICST_CRET or ICST_SRET to calculate return address location. (__tpf_eh_return): Handle skip trace addresses.
This commit is contained in:
parent
535ce76acb
commit
b749b5ec58
|
@ -1,3 +1,17 @@
|
||||||
|
2020-04-03 Jim Johnston <jjohnst@us.ibm.com>
|
||||||
|
|
||||||
|
* config/s390/tpf-unwind.h (MIN_PATRANGE, MAX_PATRANGE)
|
||||||
|
(TPFRA_OFFSET): Macros removed.
|
||||||
|
(CP_CNF, cinfc_fast, CINFC_CMRESET, CINTFC_CMCENBKST)
|
||||||
|
(CINTFC_CMCENBKED, ICST_CRET, ICST_SRET, LOWCORE_PAGE3_ADDR)
|
||||||
|
(PG3_SKIPPING_OFFSET): New macros.
|
||||||
|
(__isPATrange): Use cinfc_fast for the check.
|
||||||
|
(__isSkipResetAddr): New function.
|
||||||
|
(s390_fallback_frame_state): Check for skip trace addresses. Use
|
||||||
|
either ICST_CRET or ICST_SRET to calculate return address
|
||||||
|
location.
|
||||||
|
(__tpf_eh_return): Handle skip trace addresses.
|
||||||
|
|
||||||
2020-03-26 Richard Earnshaw <rearnsha@arm.com>
|
2020-03-26 Richard Earnshaw <rearnsha@arm.com>
|
||||||
|
|
||||||
PR target/94220
|
PR target/94220
|
||||||
|
|
|
@ -32,20 +32,29 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||||
Description: This function simply checks to see if the address
|
Description: This function simply checks to see if the address
|
||||||
passed to it is in the CP pat code range. */
|
passed to it is in the CP pat code range. */
|
||||||
|
|
||||||
#define MIN_PATRANGE 0x10000
|
#define CP_CNF 0x000000000000c18u /* location of BSS CINFC pointer */
|
||||||
#define MAX_PATRANGE 0x800000
|
#define cinfc_fast(TAG) (void *) \
|
||||||
|
*((unsigned long *) *(unsigned long *) (CP_CNF) + (TAG))
|
||||||
|
#define CINFC_CMRESET 187
|
||||||
|
#define CINTFC_CMCENBKST 431
|
||||||
|
#define CINTFC_CMCENBKED 432
|
||||||
|
|
||||||
static inline unsigned int
|
static inline unsigned int
|
||||||
__isPATrange (void *addr)
|
__isPATrange (void *addr)
|
||||||
{
|
{
|
||||||
if (addr > (void *)MIN_PATRANGE && addr < (void *)MAX_PATRANGE)
|
return !!(addr > cinfc_fast (CINTFC_CMCENBKST)
|
||||||
return 1;
|
&& addr < cinfc_fast (CINTFC_CMCENBKED));
|
||||||
else
|
}
|
||||||
return 0;
|
|
||||||
|
static inline unsigned int
|
||||||
|
__isSkipResetAddr (void *addr)
|
||||||
|
{
|
||||||
|
return !!(addr == cinfc_fast (CINFC_CMRESET));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TPF return address offset from start of stack frame. */
|
/* TPF return address offset from start of stack frame. */
|
||||||
#define TPFRA_OFFSET 168
|
#define ICST_CRET 168
|
||||||
|
#define ICST_SRET 320
|
||||||
|
|
||||||
/* Exceptions macro defined for TPF so that functions without
|
/* Exceptions macro defined for TPF so that functions without
|
||||||
dwarf frame information can be used with exceptions. */
|
dwarf frame information can be used with exceptions. */
|
||||||
|
@ -63,12 +72,12 @@ s390_fallback_frame_state (struct _Unwind_Context *context,
|
||||||
(((unsigned long int) context->cfa) - STACK_POINTER_OFFSET));
|
(((unsigned long int) context->cfa) - STACK_POINTER_OFFSET));
|
||||||
|
|
||||||
/* Are we going through special linkage code? */
|
/* Are we going through special linkage code? */
|
||||||
if (__isPATrange (context->ra))
|
if (__isPATrange (context->ra) || __isSkipResetAddr (context->ra))
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Our return register isn't zero for end of stack, so
|
/* Our return register isn't zero for end of stack, so
|
||||||
check backward stackpointer to see if it is zero. */
|
check backward stackpointer to see if it is zero. */
|
||||||
if (regs == NULL)
|
if (regs == 0)
|
||||||
return _URC_END_OF_STACK;
|
return _URC_END_OF_STACK;
|
||||||
|
|
||||||
/* No stack frame. */
|
/* No stack frame. */
|
||||||
|
@ -83,11 +92,18 @@ s390_fallback_frame_state (struct _Unwind_Context *context,
|
||||||
fs->regs.reg[i].loc.reg = i;
|
fs->regs.reg[i].loc.reg = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ... except for %r14, which is stored at CFA-112
|
/* ... except for %r14, which is stored at CFA+offset where offset
|
||||||
and used as return address. */
|
is displacment of ICST_CRET or ICST_SRET from CFA */
|
||||||
|
if ( __isPATrange(context->ra) ) {
|
||||||
fs->regs.reg[14].how = REG_SAVED_OFFSET;
|
fs->regs.reg[14].how = REG_SAVED_OFFSET;
|
||||||
fs->regs.reg[14].loc.offset = TPFRA_OFFSET - STACK_POINTER_OFFSET;
|
fs->regs.reg[14].loc.offset = ICST_CRET - STACK_POINTER_OFFSET;
|
||||||
fs->retaddr_column = 14;
|
fs->retaddr_column = 14;
|
||||||
|
} else {
|
||||||
|
fs->regs.reg[14].how = REG_SAVED_OFFSET;
|
||||||
|
fs->regs.reg[14].loc.offset = ICST_SRET - STACK_POINTER_OFFSET;
|
||||||
|
fs->retaddr_column = 14;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
return _URC_NO_REASON;
|
return _URC_NO_REASON;
|
||||||
}
|
}
|
||||||
|
@ -140,6 +156,9 @@ s390_fallback_frame_state (struct _Unwind_Context *context,
|
||||||
#define TPFAREA_SIZE STACK_POINTER_OFFSET-TPFAREA_OFFSET
|
#define TPFAREA_SIZE STACK_POINTER_OFFSET-TPFAREA_OFFSET
|
||||||
#define INVALID_RETURN 0
|
#define INVALID_RETURN 0
|
||||||
|
|
||||||
|
#define LOWCORE_PAGE3_ADDR 4032
|
||||||
|
#define PG3_SKIPPING_OFFSET 18
|
||||||
|
|
||||||
void * __tpf_eh_return (void *target, void *origRA);
|
void * __tpf_eh_return (void *target, void *origRA);
|
||||||
|
|
||||||
void *
|
void *
|
||||||
|
@ -148,56 +167,47 @@ __tpf_eh_return (void *target, void *origRA)
|
||||||
Dl_info targetcodeInfo, currentcodeInfo;
|
Dl_info targetcodeInfo, currentcodeInfo;
|
||||||
int retval;
|
int retval;
|
||||||
void *current, *stackptr, *destination_frame;
|
void *current, *stackptr, *destination_frame;
|
||||||
|
unsigned char *skipFlagAddress;
|
||||||
unsigned long int shifter;
|
unsigned long int shifter;
|
||||||
bool is_a_stub, frameDepth2, firstIteration;
|
bool is_a_stub;
|
||||||
|
|
||||||
is_a_stub = false;
|
is_a_stub = false;
|
||||||
frameDepth2 = false;
|
|
||||||
firstIteration = true;
|
|
||||||
|
|
||||||
/* Get code info for target return's address. */
|
/* Get code info for target return's address. */
|
||||||
retval = dladdr (target, &targetcodeInfo);
|
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). */
|
/* Ensure the code info is valid (for target). */
|
||||||
if (retval != INVALID_RETURN)
|
if (retval != INVALID_RETURN)
|
||||||
{
|
{
|
||||||
/* Get the stack pointer of the first stack frame beyond the
|
/* Begin climbing stack searching for target address. */
|
||||||
unwinder or if exists the calling C++ runtime function (e.g.,
|
stackptr = (void *) *(CURRENT_STACK_PTR());
|
||||||
__cxa_throw). */
|
|
||||||
if (!frameDepth2)
|
/* Get return address based on our stackptr. */
|
||||||
stackptr = (void *) *((unsigned long int *) (*(PREVIOUS_STACK_PTR())));
|
current = (void *) *(unsigned long *) (stackptr + RA_OFFSET);
|
||||||
else
|
|
||||||
stackptr = (void *) *(PREVIOUS_STACK_PTR());
|
/* Is current return address our initiating exception stack
|
||||||
|
frame? If not, climb the stack one more frame. */
|
||||||
|
if (current != origRA) {
|
||||||
|
stackptr = (void *) *(unsigned long *) stackptr;
|
||||||
|
}
|
||||||
|
|
||||||
/* Begin looping through stack frames. Stop if invalid
|
/* Begin looping through stack frames. Stop if invalid
|
||||||
code information is retrieved or if a match between the
|
code information is retrieved or if a match between the
|
||||||
current stack frame iteration shared object's address
|
current stack frame iteration shared object's address
|
||||||
matches that of the target, calculated above. */
|
matches that of the target, calculated above. */
|
||||||
do
|
do
|
||||||
{
|
|
||||||
if (!frameDepth2 || (frameDepth2 && !firstIteration))
|
|
||||||
{
|
{
|
||||||
/* Get return address based on our stackptr iterator. */
|
/* Get return address based on our stackptr iterator. */
|
||||||
current = (void *) *((unsigned long int *)
|
current = (void *) *(unsigned long *) (stackptr + RA_OFFSET);
|
||||||
(stackptr + RA_OFFSET));
|
|
||||||
|
|
||||||
/* Is it a Pat Stub? */
|
/* Is it a Pat Stub? */
|
||||||
if (__isPATrange (current))
|
if (__isPATrange (current)
|
||||||
|
|| (__isSkipResetAddr (current)
|
||||||
|
&& __isPATrange ((void *) *(unsigned long *) (stackptr
|
||||||
|
+ ICST_SRET))))
|
||||||
{
|
{
|
||||||
/* Yes it was, get real return address in TPF stack area. */
|
/* Yes it was, get real return address in TPF stack area. */
|
||||||
current = (void *) *((unsigned long int *)
|
current = (void *) *(unsigned long *) (stackptr + ICST_CRET);
|
||||||
(stackptr + TPFRA_OFFSET))
|
|
||||||
is_a_stub = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
current = (void *) *((unsigned long int *)
|
|
||||||
(stackptr + TPFRA_OFFSET));
|
|
||||||
is_a_stub = true;
|
is_a_stub = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,8 +237,8 @@ __tpf_eh_return (void *target, void *origRA)
|
||||||
/* Now overlay the
|
/* Now overlay the
|
||||||
real target address into the TPF stack area of
|
real target address into the TPF stack area of
|
||||||
the target frame we are jumping to. */
|
the target frame we are jumping to. */
|
||||||
*((unsigned long int *) (destination_frame +
|
*(unsigned long *) (destination_frame + ICST_CRET) =
|
||||||
TPFRA_OFFSET)) = (unsigned long int) target;
|
(unsigned long) target;
|
||||||
|
|
||||||
/* Before returning the desired pat stub address to
|
/* Before returning the desired pat stub address to
|
||||||
the exception handling unwinder so that it can
|
the exception handling unwinder so that it can
|
||||||
|
@ -237,10 +247,7 @@ __tpf_eh_return (void *target, void *origRA)
|
||||||
This is necessary for CTOA stubs.
|
This is necessary for CTOA stubs.
|
||||||
Otherwise we leap one byte past where we want to
|
Otherwise we leap one byte past where we want to
|
||||||
go to in the TPF pat stub linkage code. */
|
go to in the TPF pat stub linkage code. */
|
||||||
if (!frameDepth2 || (frameDepth2 && !firstIteration))
|
shifter = *(unsigned long *) (stackptr + RA_OFFSET);
|
||||||
shifter = *((unsigned long int *) (stackptr + RA_OFFSET));
|
|
||||||
else
|
|
||||||
shifter = (unsigned long int) origRA;
|
|
||||||
|
|
||||||
shifter &= ~1ul;
|
shifter &= ~1ul;
|
||||||
|
|
||||||
|
@ -252,6 +259,13 @@ __tpf_eh_return (void *target, void *origRA)
|
||||||
in linkage. */
|
in linkage. */
|
||||||
shifter = shifter - 4;
|
shifter = shifter - 4;
|
||||||
|
|
||||||
|
/* Reset the Function Trace Skipping Switch to re-enable */
|
||||||
|
/* recording Trace entries if it was turned off. */
|
||||||
|
skipFlagAddress =
|
||||||
|
(unsigned char *) *(unsigned long *) LOWCORE_PAGE3_ADDR;
|
||||||
|
skipFlagAddress += PG3_SKIPPING_OFFSET;
|
||||||
|
*skipFlagAddress = '\x00';
|
||||||
|
|
||||||
return (void *) shifter;
|
return (void *) shifter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,14 +274,18 @@ __tpf_eh_return (void *target, void *origRA)
|
||||||
stackptr = (void *) *(unsigned long int *) stackptr;
|
stackptr = (void *) *(unsigned long int *) stackptr;
|
||||||
|
|
||||||
is_a_stub = false;
|
is_a_stub = false;
|
||||||
firstIteration = false;
|
|
||||||
|
|
||||||
} while (stackptr && retval != INVALID_RETURN
|
} while (stackptr && retval != INVALID_RETURN
|
||||||
&& targetcodeInfo.dli_fbase != currentcodeInfo.dli_fbase);
|
&& targetcodeInfo.dli_fbase != currentcodeInfo.dli_fbase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reset the Function Trace Skipping Switch to re-enable */
|
||||||
|
/* recording Trace entries if it was turned off. */
|
||||||
|
skipFlagAddress = (unsigned char *) *(unsigned long *) LOWCORE_PAGE3_ADDR;
|
||||||
|
skipFlagAddress += PG3_SKIPPING_OFFSET;
|
||||||
|
*skipFlagAddress = '\x00';
|
||||||
|
|
||||||
/* No pat stub found, could be a problem? Simply return unmodified
|
/* No pat stub found, could be a problem? Simply return unmodified
|
||||||
target address. */
|
target address. */
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue