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> 2020-03-26 Richard Earnshaw <rearnsha@arm.com>
PR target/94220 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 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 */
fs->regs.reg[14].how = REG_SAVED_OFFSET; if ( __isPATrange(context->ra) ) {
fs->regs.reg[14].loc.offset = TPFRA_OFFSET - STACK_POINTER_OFFSET; fs->regs.reg[14].how = REG_SAVED_OFFSET;
fs->retaddr_column = 14; 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; 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,30 +167,29 @@ __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
@ -179,27 +197,19 @@ __tpf_eh_return (void *target, void *origRA)
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. */
{ current = (void *) *(unsigned long *) (stackptr + RA_OFFSET);
/* Get return address based on our stackptr iterator. */
current = (void *) *((unsigned long int *)
(stackptr + RA_OFFSET));
/* Is it a Pat Stub? */ /* Is it a Pat Stub? */
if (__isPATrange (current)) if (__isPATrange (current)
{ || (__isSkipResetAddr (current)
/* Yes it was, get real return address in TPF stack area. */ && __isPATrange ((void *) *(unsigned long *) (stackptr
current = (void *) *((unsigned long int *) + ICST_SRET))))
(stackptr + TPFRA_OFFSET)) {
is_a_stub = true; /* Yes it was, get real return address in TPF stack area. */
} current = (void *) *(unsigned long *) (stackptr + ICST_CRET);
} is_a_stub = true;
else }
{
current = (void *) *((unsigned long int *)
(stackptr + TPFRA_OFFSET));
is_a_stub = true;
}
/* Get codeinfo on RA so that we can figure out /* Get codeinfo on RA so that we can figure out
the module address. */ the module address. */
@ -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;
} }