diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c
index 54b5c89e5e3..2d5c3f99dd8 100644
--- a/gdb/s390-tdep.c
+++ b/gdb/s390-tdep.c
@@ -2520,32 +2520,24 @@ s390_prologue_frame_unwind_cache (frame_info_ptr this_frame,
   return 1;
 }
 
-/* Unwind THIS_FRAME and write the information into unwind cache INFO using
-   back chain unwinding.  Helper for s390_frame_unwind_cache.  */
+/* Unwind THIS_FRAME using back chain unwinding for the ABI described by
+   WORD_SIZE, BYTE_ORDER, BACKCHAIN_IDX, SP_IDX and PC_IDX.  If successful,
+   write the information into unwind cache INFO and return true, otherwise
+   return false.  Helper for s390_backchain_frame_unwind_cache.  */
 
-static void
-s390_backchain_frame_unwind_cache (frame_info_ptr this_frame,
-				   struct s390_unwind_cache *info)
+static bool
+try_backchain (frame_info_ptr this_frame, struct s390_unwind_cache *info,
+	       int word_size, enum bfd_endian byte_order, int backchain_idx,
+	       int sp_idx, int pc_idx)
 {
-  struct gdbarch *gdbarch = get_frame_arch (this_frame);
-  int word_size = gdbarch_ptr_bit (gdbarch) / 8;
-  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   CORE_ADDR backchain;
-  ULONGEST reg;
   LONGEST sp, tmp;
-  int i;
-
-  /* Set up ABI call-saved/call-clobbered registers.  */
-  for (i = 0; i < S390_NUM_REGS; i++)
-    if (!s390_register_call_saved (gdbarch, i))
-      info->saved_regs[i].set_unknown ();
-
-  /* CC is always call-clobbered.  */
-  info->saved_regs[S390_PSWM_REGNUM].set_unknown ();
+  ULONGEST reg;
 
   /* Get the backchain.  */
   reg = get_frame_register_unsigned (this_frame, S390_SP_REGNUM);
-  if (!safe_read_memory_integer (reg, word_size, byte_order, &tmp))
+  if (!safe_read_memory_integer (reg + backchain_idx * word_size, word_size,
+				 byte_order, &tmp))
     tmp = 0;
   backchain = (CORE_ADDR) tmp;
 
@@ -2554,15 +2546,17 @@ s390_backchain_frame_unwind_cache (frame_info_ptr this_frame,
      save area pointed to by the backchain in fact links back to
      the save area.  */
   if (backchain != 0
-      && safe_read_memory_integer (backchain + 15*word_size,
-				   word_size, byte_order, &sp)
+      && safe_read_memory_integer (backchain + sp_idx * word_size, word_size,
+				   byte_order, &sp)
       && (CORE_ADDR)sp == backchain)
     {
       /* We don't know which registers were saved, but it will have
 	 to be at least %r14 and %r15.  This will allow us to continue
 	 unwinding, but other prev-frame registers may be incorrect ...  */
-      info->saved_regs[S390_SP_REGNUM].set_addr (backchain + 15*word_size);
-      info->saved_regs[S390_RETADDR_REGNUM].set_addr (backchain + 14*word_size);
+      info->saved_regs[S390_SP_REGNUM].set_addr (backchain
+						 + sp_idx * word_size);
+      info->saved_regs[S390_RETADDR_REGNUM].set_addr (backchain
+						      + pc_idx * word_size);
 
       /* Function return will set PC to %r14.  */
       info->saved_regs[S390_PSWA_REGNUM]
@@ -2570,10 +2564,40 @@ s390_backchain_frame_unwind_cache (frame_info_ptr this_frame,
 
       /* We use the current value of the frame register as local_base,
 	 and the top of the register save area as frame_base.  */
-      info->frame_base = backchain + 16*word_size + 32;
+      info->frame_base = backchain + 16 * word_size + 32;
       info->local_base = reg;
+
+      return true;
     }
 
+  return false;
+}
+
+/* Unwind THIS_FRAME and write the information into unwind cache INFO using
+   back chain unwinding.  Helper for s390_frame_unwind_cache.  */
+
+static void
+s390_backchain_frame_unwind_cache (frame_info_ptr this_frame,
+				   struct s390_unwind_cache *info)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  int word_size = gdbarch_ptr_bit (gdbarch) / 8;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int i;
+
+  /* Set up ABI call-saved/call-clobbered registers.  */
+  for (i = 0; i < S390_NUM_REGS; i++)
+    if (!s390_register_call_saved (gdbarch, i))
+      info->saved_regs[i].set_unknown ();
+
+  /* CC is always call-clobbered.  */
+  info->saved_regs[S390_PSWM_REGNUM].set_unknown ();
+
+  /* Try the regular ABI.  */
+  if (!try_backchain (this_frame, info, word_size, byte_order, 0, 15, 14))
+    /* Try the packed stack ABI.  */
+    try_backchain (this_frame, info, word_size, byte_order, 19, 18, 17);
+
   info->func = get_frame_pc (this_frame);
 }
 
