S/390 zTPF: Handle skip trace addresses when unwinding
authorJim Johnston <jjohnst@us.ibm.com>
Fri, 3 Apr 2020 06:46:11 +0000 (08:46 +0200)
committerAndreas Krebbel <krebbel@linux.ibm.com>
Fri, 3 Apr 2020 06:46:11 +0000 (08:46 +0200)
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.

libgcc/ChangeLog
libgcc/config/s390/tpf-unwind.h

index c5ff4f63c7d1b11915fffe8ead7867114c7d65bb..7548e34764033fa8e68d77d33153ef71fa9c74d6 100644 (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
index 2bd5493bb715af8c551ec98ac6b098b5f4a7518f..fadc06b5e596c54a71703bbe42c74a7c12d14016 100644 (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));
-
-              /* 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;
-            }
+         /* Get return address based on our stackptr iterator.  */
+         current = (void *) *(unsigned long *) (stackptr + RA_OFFSET);
+
+         /* 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;
 }
-