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:
Jim Johnston 2020-04-03 08:46:11 +02:00 committed by Andreas Krebbel
parent 535ce76acb
commit b749b5ec58
2 changed files with 88 additions and 56 deletions

View File

@ -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>
PR target/94220

View File

@ -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
passed to it is in the CP pat code range. */
#define MIN_PATRANGE 0x10000
#define MAX_PATRANGE 0x800000
#define CP_CNF 0x000000000000c18u /* location of BSS CINFC pointer */
#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
__isPATrange (void *addr)
{
if (addr > (void *)MIN_PATRANGE && addr < (void *)MAX_PATRANGE)
return 1;
else
return 0;
return !!(addr > cinfc_fast (CINTFC_CMCENBKST)
&& addr < cinfc_fast (CINTFC_CMCENBKED));
}
static inline unsigned int
__isSkipResetAddr (void *addr)
{
return !!(addr == cinfc_fast (CINFC_CMRESET));
}
/* 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
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));
/* 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
check backward stackpointer to see if it is zero. */
if (regs == NULL)
if (regs == 0)
return _URC_END_OF_STACK;
/* No stack frame. */
@ -83,11 +92,18 @@ s390_fallback_frame_state (struct _Unwind_Context *context,
fs->regs.reg[i].loc.reg = i;
}
/* ... except for %r14, which is stored at CFA-112
and used as return address. */
fs->regs.reg[14].how = REG_SAVED_OFFSET;
fs->regs.reg[14].loc.offset = TPFRA_OFFSET - STACK_POINTER_OFFSET;
fs->retaddr_column = 14;
/* ... except for %r14, which is stored at CFA+offset where offset
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].loc.offset = ICST_CRET - STACK_POINTER_OFFSET;
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;
}
@ -140,6 +156,9 @@ s390_fallback_frame_state (struct _Unwind_Context *context,
#define TPFAREA_SIZE STACK_POINTER_OFFSET-TPFAREA_OFFSET
#define INVALID_RETURN 0
#define LOWCORE_PAGE3_ADDR 4032
#define PG3_SKIPPING_OFFSET 18
void * __tpf_eh_return (void *target, void *origRA);
void *
@ -148,30 +167,29 @@ __tpf_eh_return (void *target, void *origRA)
Dl_info targetcodeInfo, currentcodeInfo;
int retval;
void *current, *stackptr, *destination_frame;
unsigned char *skipFlagAddress;
unsigned long int shifter;
bool is_a_stub, frameDepth2, firstIteration;
bool is_a_stub;
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 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 climbing stack searching for target address. */
stackptr = (void *) *(CURRENT_STACK_PTR());
/* Get return address based on our stackptr. */
current = (void *) *(unsigned long *) (stackptr + RA_OFFSET);
/* 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
code information is retrieved or if a match between the
@ -179,27 +197,19 @@ __tpf_eh_return (void *target, void *origRA)
matches that of the target, calculated above. */
do
{
if (!frameDepth2 || (frameDepth2 && !firstIteration))
{
/* Get return address based on our stackptr iterator. */
current = (void *) *((unsigned long int *)
(stackptr + RA_OFFSET));
/* Get return address based on our stackptr iterator. */
current = (void *) *(unsigned long *) (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
{
current = (void *) *((unsigned long int *)
(stackptr + TPFRA_OFFSET));
is_a_stub = true;
}
/* Is it a Pat Stub? */
if (__isPATrange (current)
|| (__isSkipResetAddr (current)
&& __isPATrange ((void *) *(unsigned long *) (stackptr
+ ICST_SRET))))
{
/* Yes it was, get real return address in TPF stack area. */
current = (void *) *(unsigned long *) (stackptr + ICST_CRET);
is_a_stub = true;
}
/* Get codeinfo on RA so that we can figure out
the module address. */
@ -227,8 +237,8 @@ __tpf_eh_return (void *target, void *origRA)
/* Now overlay the
real target address into the TPF stack area of
the target frame we are jumping to. */
*((unsigned long int *) (destination_frame +
TPFRA_OFFSET)) = (unsigned long int) target;
*(unsigned long *) (destination_frame + ICST_CRET) =
(unsigned long) target;
/* Before returning the desired pat stub address to
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.
Otherwise we leap one byte past where we want to
go to in the TPF pat stub linkage code. */
if (!frameDepth2 || (frameDepth2 && !firstIteration))
shifter = *((unsigned long int *) (stackptr + RA_OFFSET));
else
shifter = (unsigned long int) origRA;
shifter = *(unsigned long *) (stackptr + RA_OFFSET);
shifter &= ~1ul;
@ -252,6 +259,13 @@ __tpf_eh_return (void *target, void *origRA)
in linkage. */
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;
}
@ -260,14 +274,18 @@ __tpf_eh_return (void *target, void *origRA)
stackptr = (void *) *(unsigned long int *) stackptr;
is_a_stub = false;
firstIteration = false;
} while (stackptr && retval != INVALID_RETURN
&& 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
target address. */
return target;
}