ChangeLog:
authorUlrich Weigand <uweigand@de.ibm.com>
Wed, 30 Nov 2011 16:06:55 +0000 (16:06 +0000)
committerUlrich Weigand <uweigand@de.ibm.com>
Wed, 30 Nov 2011 16:06:55 +0000 (16:06 +0000)
* s390-nat.c (SUBOFF): Remove.
(s390_native_supply, s390_native_collect): New functions.
(supply_gregset, supply_fpregset): Use s390_native_supply.
(fill_gregset, fill_fpregset): Use s390_native_collect.

* s390-tdep.c (s390_pseudo_register_reggroup_p): Update comment.
(s390_unwind_pseudo_register): New function.
(s390_prologue_frame_unwind_cache): Unwind PSW address and mask
registers instead of PC and CC.
(s390_backchain_frame_unwind_cache): Likewise.
(s390_sigtramp_frame_unwind_cache): Do not unwind PC, CC, or
full GPR pseudos.
(s390_trad_frame_prev_register): New function.
(s390_frame_prev_register): Use it.
(s390_sigtramp_frame_prev_register): Likewise.
(s390_dwarf2_prev_register): Use s390_unwind_pseudo_register.
(s390_dwarf2_frame_init_reg): Unwind PSW address and mask.  Use
special callback to unwind any pseudo.

* features/s390-core32.xml: Add pswm/pswa to save/restore group.
* features/s390-core64.xml: Likewise.
* features/s390x-core64.xml: Likewise.
* features/s390-linux32.c: Regenerate.
* features/s390-linux64.c: Likewise.
* features/s390x-linux64.c: Likewise.

gdbserver/ChangeLog:

* linux-s390-low.c (s390_collect_ptrace_register): Fully convert
PSW address/mask between 8-byte and 16-byte formats.
(s390_supply_ptrace_register): Likewise.
(s390_get_pc, s390_set_pc): 4-byte PSW address always includes
basic addressing mode bit.

gdb/ChangeLog
gdb/features/s390-core32.xml
gdb/features/s390-core64.xml
gdb/features/s390-linux32.c
gdb/features/s390-linux64.c
gdb/features/s390x-core64.xml
gdb/features/s390x-linux64.c
gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-s390-low.c
gdb/s390-nat.c
gdb/s390-tdep.c

index 49f2945601626670369b6c75e5313c5e4e4ec4a0..dcaf7776fbf9b49a67b4bf7a82876163bc9d64f6 100644 (file)
@@ -1,3 +1,31 @@
+2011-11-30  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * s390-nat.c (SUBOFF): Remove.
+       (s390_native_supply, s390_native_collect): New functions.
+       (supply_gregset, supply_fpregset): Use s390_native_supply.
+       (fill_gregset, fill_fpregset): Use s390_native_collect.
+
+       * s390-tdep.c (s390_pseudo_register_reggroup_p): Update comment.
+       (s390_unwind_pseudo_register): New function.
+       (s390_prologue_frame_unwind_cache): Unwind PSW address and mask
+       registers instead of PC and CC.
+       (s390_backchain_frame_unwind_cache): Likewise.
+       (s390_sigtramp_frame_unwind_cache): Do not unwind PC, CC, or
+       full GPR pseudos.
+       (s390_trad_frame_prev_register): New function.
+       (s390_frame_prev_register): Use it.
+       (s390_sigtramp_frame_prev_register): Likewise.
+       (s390_dwarf2_prev_register): Use s390_unwind_pseudo_register.
+       (s390_dwarf2_frame_init_reg): Unwind PSW address and mask.  Use
+       special callback to unwind any pseudo.
+
+       * features/s390-core32.xml: Add pswm/pswa to save/restore group.
+       * features/s390-core64.xml: Likewise.
+       * features/s390x-core64.xml: Likewise.
+       * features/s390-linux32.c: Regenerate.
+       * features/s390-linux64.c: Likewise.
+       * features/s390x-linux64.c: Likewise.
+
 2011-11-30  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * s390-tdep.c (s390_gdbarch_init): Call set_gdbarch_get_siginfo_type.
index 3c0937ad4252ee3544b096b8d43c39ee66535ffc..989e55540e0971c1513082c66eb002e9ba55ab1f 100644 (file)
@@ -7,8 +7,8 @@
 
 <!DOCTYPE feature SYSTEM "gdb-target.dtd">
 <feature name="org.gnu.gdb.s390.core">
-  <reg name="pswm" bitsize="32" type="uint32" group="psw" save-restore="no"/>
-  <reg name="pswa" bitsize="32" type="uint32" group="psw" save-restore="no"/>
+  <reg name="pswm" bitsize="32" type="uint32" group="psw"/>
+  <reg name="pswa" bitsize="32" type="uint32" group="psw"/>
   <reg name="r0" bitsize="32" type="uint32" group="general"/>
   <reg name="r1" bitsize="32" type="uint32" group="general"/>
   <reg name="r2" bitsize="32" type="uint32" group="general"/>
index 7abe38d890597446bd3d78336a56b34c3b7dbfa6..d5998c9ddf6ddf4185583f06f7aca70acfc0cc94 100644 (file)
@@ -7,8 +7,8 @@
 
 <!DOCTYPE feature SYSTEM "gdb-target.dtd">
 <feature name="org.gnu.gdb.s390.core">
-  <reg name="pswm" bitsize="32" type="uint32" group="psw" save-restore="no"/>
-  <reg name="pswa" bitsize="32" type="uint32" group="psw" save-restore="no"/>
+  <reg name="pswm" bitsize="32" type="uint32" group="psw"/>
+  <reg name="pswa" bitsize="32" type="uint32" group="psw"/>
   <reg name="r0h" bitsize="32" type="uint32" group="upper"/>
   <reg name="r0l" bitsize="32" type="uint32" group="lower"/>
   <reg name="r1h" bitsize="32" type="uint32" group="upper"/>
index 0ff386821646403d3fa76f56e6621c3b46d4a163..0e28c726a39c246207e09f80d5834814e6cf4e6d 100644 (file)
@@ -1,6 +1,7 @@
 /* THIS FILE IS GENERATED.  Original: s390-linux32.xml */
 
 #include "defs.h"
+#include "osabi.h"
 #include "target-descriptions.h"
 
 struct target_desc *tdesc_s390_linux32;
@@ -14,8 +15,8 @@ initialize_tdesc_s390_linux32 (void)
   set_tdesc_architecture (result, bfd_scan_arch ("s390:31-bit"));
 
   feature = tdesc_create_feature (result, "org.gnu.gdb.s390.core");
-  tdesc_create_reg (feature, "pswm", 0, 0, "psw", 32, "uint32");
-  tdesc_create_reg (feature, "pswa", 1, 0, "psw", 32, "uint32");
+  tdesc_create_reg (feature, "pswm", 0, 1, "psw", 32, "uint32");
+  tdesc_create_reg (feature, "pswa", 1, 1, "psw", 32, "uint32");
   tdesc_create_reg (feature, "r0", 2, 1, "general", 32, "uint32");
   tdesc_create_reg (feature, "r1", 3, 1, "general", 32, "uint32");
   tdesc_create_reg (feature, "r2", 4, 1, "general", 32, "uint32");
index 1e39fc30ca3d6686cdf92f92cffbf3ea595393ec..e7acfe284c713d8d37a53f963dc7bca61e0ad77c 100644 (file)
@@ -1,6 +1,7 @@
 /* THIS FILE IS GENERATED.  Original: s390-linux64.xml */
 
 #include "defs.h"
+#include "osabi.h"
 #include "target-descriptions.h"
 
 struct target_desc *tdesc_s390_linux64;
@@ -14,8 +15,8 @@ initialize_tdesc_s390_linux64 (void)
   set_tdesc_architecture (result, bfd_scan_arch ("s390:31-bit"));
 
   feature = tdesc_create_feature (result, "org.gnu.gdb.s390.core");
-  tdesc_create_reg (feature, "pswm", 0, 0, "psw", 32, "uint32");
-  tdesc_create_reg (feature, "pswa", 1, 0, "psw", 32, "uint32");
+  tdesc_create_reg (feature, "pswm", 0, 1, "psw", 32, "uint32");
+  tdesc_create_reg (feature, "pswa", 1, 1, "psw", 32, "uint32");
   tdesc_create_reg (feature, "r0h", 2, 1, "upper", 32, "uint32");
   tdesc_create_reg (feature, "r0l", 3, 1, "lower", 32, "uint32");
   tdesc_create_reg (feature, "r1h", 4, 1, "upper", 32, "uint32");
index eca8246f566240e06b818a445d0e690e7f7d7246..2f019039e04f377397d2d09351cde1f0aba715c6 100644 (file)
@@ -7,8 +7,8 @@
 
 <!DOCTYPE feature SYSTEM "gdb-target.dtd">
 <feature name="org.gnu.gdb.s390.core">
-  <reg name="pswm" bitsize="64" type="uint64" group="psw" save-restore="no"/>
-  <reg name="pswa" bitsize="64" type="uint64" group="psw" save-restore="no"/>
+  <reg name="pswm" bitsize="64" type="uint64" group="psw"/>
+  <reg name="pswa" bitsize="64" type="uint64" group="psw"/>
   <reg name="r0" bitsize="64" type="uint64" group="general"/>
   <reg name="r1" bitsize="64" type="uint64" group="general"/>
   <reg name="r2" bitsize="64" type="uint64" group="general"/>
index 91d2da9930146105a4874bcc6b9547bd45c31747..06a9339b05a945e01c8dbe53809f98e95d438625 100644 (file)
@@ -1,6 +1,7 @@
 /* THIS FILE IS GENERATED.  Original: s390x-linux64.xml */
 
 #include "defs.h"
+#include "osabi.h"
 #include "target-descriptions.h"
 
 struct target_desc *tdesc_s390x_linux64;
@@ -14,8 +15,8 @@ initialize_tdesc_s390x_linux64 (void)
   set_tdesc_architecture (result, bfd_scan_arch ("s390:64-bit"));
 
   feature = tdesc_create_feature (result, "org.gnu.gdb.s390.core");
-  tdesc_create_reg (feature, "pswm", 0, 0, "psw", 64, "uint64");
-  tdesc_create_reg (feature, "pswa", 1, 0, "psw", 64, "uint64");
+  tdesc_create_reg (feature, "pswm", 0, 1, "psw", 64, "uint64");
+  tdesc_create_reg (feature, "pswa", 1, 1, "psw", 64, "uint64");
   tdesc_create_reg (feature, "r0", 2, 1, "general", 64, "uint64");
   tdesc_create_reg (feature, "r1", 3, 1, "general", 64, "uint64");
   tdesc_create_reg (feature, "r2", 4, 1, "general", 64, "uint64");
index f383edc2afde571fb3a8af7d4df0950cf661f8f1..464d9dfee694301802c4443278f436742cb6b130 100644 (file)
@@ -1,3 +1,11 @@
+2011-11-30  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * linux-s390-low.c (s390_collect_ptrace_register): Fully convert
+       PSW address/mask between 8-byte and 16-byte formats.
+       (s390_supply_ptrace_register): Likewise.
+       (s390_get_pc, s390_set_pc): 4-byte PSW address always includes
+       basic addressing mode bit.
+
 2011-11-24  Stan Shebs  <stan@codesourcery.com>
 
        * tracepoint.c (cmd_qtstatus): Use plongest instead of %llx.
index 5c38e434c11551e347d7e7265e4be44605d84314..898b75768433067947f06ca7a6f493ba36d67148 100644 (file)
@@ -126,16 +126,27 @@ s390_collect_ptrace_register (struct regcache *regcache, int regno, char *buf)
          collect_register (regcache, (regno & ~1) + 1,
                            buf + sizeof (long) - size);
        }
-      else if (regaddr == PT_PSWADDR
-              || (regaddr >= PT_GPR0 && regaddr <= PT_GPR15))
+      else if (regaddr == PT_PSWMASK)
+       {
+         /* Convert 4-byte PSW mask to 8 bytes by clearing bit 12 and copying
+            the basic addressing mode bit from the PSW address.  */
+         char *addr = alloca (register_size (regno ^ 1));
+         collect_register (regcache, regno, buf);
+         collect_register (regcache, regno ^ 1, addr);
+         buf[1] &= ~0x8;
+         buf[size] |= (addr[0] & 0x80);
+       }
+      else if (regaddr == PT_PSWADDR)
+       {
+         /* Convert 4-byte PSW address to 8 bytes by clearing the addressing
+            mode bit (which gets copied to the PSW mask instead).  */
+         collect_register (regcache, regno, buf + sizeof (long) - size);
+         buf[sizeof (long) - size] &= ~0x80;
+       }
+      else if (regaddr >= PT_GPR0 && regaddr <= PT_GPR15)
        collect_register (regcache, regno, buf + sizeof (long) - size);
       else
        collect_register (regcache, regno, buf);
-
-      /* When debugging a 32-bit inferior on a 64-bit host, make sure
-        the 31-bit addressing mode bit is set in the PSW mask.  */
-      if (regaddr == PT_PSWMASK)
-       buf[size] |= 0x80;
     }
   else
     collect_register (regcache, regno, buf);
@@ -157,8 +168,35 @@ s390_supply_ptrace_register (struct regcache *regcache,
          supply_register (regcache, (regno & ~1) + 1,
                           buf + sizeof (long) - size);
        }
-      else if (regaddr == PT_PSWADDR
-              || (regaddr >= PT_GPR0 && regaddr <= PT_GPR15))
+      else if (regaddr == PT_PSWMASK)
+       {
+         /* Convert 8-byte PSW mask to 4 bytes by setting bit 12 and copying
+            the basic addressing mode into the PSW address.  */
+         char *mask = alloca (size);
+         char *addr = alloca (register_size (regno ^ 1));
+         memcpy (mask, buf, size);
+         mask[1] |= 0x8;
+         supply_register (regcache, regno, mask);
+
+         collect_register (regcache, regno ^ 1, addr);
+         addr[0] &= ~0x80;
+         addr[0] |= (buf[size] & 0x80);
+         supply_register (regcache, regno ^ 1, addr);
+       }
+      else if (regaddr == PT_PSWADDR)
+       {
+         /* Convert 8-byte PSW address to 4 bytes by truncating, but
+            keeping the addressing mode bit (which was set from the mask).  */
+         char *addr = alloca (size);
+         char amode;
+         collect_register (regcache, regno, addr);
+         amode = addr[0] & 0x80;
+         memcpy (addr, buf + sizeof (long) - size, size);
+         addr[0] &= ~0x80;
+         addr[0] |= amode;
+         supply_register (regcache, regno, addr);
+       }
+      else if (regaddr >= PT_GPR0 && regaddr <= PT_GPR15)
        supply_register (regcache, regno, buf + sizeof (long) - size);
       else
        supply_register (regcache, regno, buf);
@@ -199,12 +237,9 @@ s390_get_pc (struct regcache *regcache)
 {
   if (register_size (0) == 4)
     {
-      unsigned int pc;
-      collect_register_by_name (regcache, "pswa", &pc);
-#ifndef __s390x__
-      pc &= 0x7fffffff;
-#endif
-      return pc;
+      unsigned int pswa;
+      collect_register_by_name (regcache, "pswa", &pswa);
+      return pswa & 0x7fffffff;
     }
   else
     {
@@ -219,11 +254,10 @@ s390_set_pc (struct regcache *regcache, CORE_ADDR newpc)
 {
   if (register_size (0) == 4)
     {
-      unsigned int pc = newpc;
-#ifndef __s390x__
-      pc |= 0x80000000;
-#endif
-      supply_register_by_name (regcache, "pswa", &pc);
+      unsigned int pswa;
+      collect_register_by_name (regcache, "pswa", &pswa);
+      pswa = (pswa & 0x80000000) | (newpc & 0x7fffffff);
+      supply_register_by_name (regcache, "pswa", &pswa);
     }
   else
     {
index 5bc88a946ab50ce09f9906a1488f4fbd6b177a78..c1eec1cc1dcdf7183061bcac15ec039e6a4c1f2a 100644 (file)
 /* When debugging a 32-bit executable running under a 64-bit kernel,
    we have to fix up the 64-bit registers we get from the kernel
    to make them look like 32-bit registers.  */
+
+static void
+s390_native_supply (struct regcache *regcache, int regno,
+                   const gdb_byte *regp, int *regmap)
+{
+  int offset = regmap[regno];
+
 #ifdef __s390x__
-#define SUBOFF(gdbarch, i) \
-       ((gdbarch_ptr_bit (gdbarch) == 32 \
-         && ((i) == S390_PSWA_REGNUM \
-             || ((i) >= S390_R0_REGNUM && (i) <= S390_R15_REGNUM)))? 4 : 0)
-#else
-#define SUBOFF(gdbarch, i) 0
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  if (offset != -1 && gdbarch_ptr_bit (gdbarch) == 32)
+    {
+      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+      if (regno == S390_PSWM_REGNUM)
+       {
+         ULONGEST pswm;
+         gdb_byte buf[4];
+
+         pswm = extract_unsigned_integer (regp + regmap[S390_PSWM_REGNUM],
+                                          8, byte_order);
+
+         store_unsigned_integer (buf, 4, byte_order, (pswm >> 32) | 0x80000);
+         regcache_raw_supply (regcache, regno, buf);
+         return;
+       }
+
+      if (regno == S390_PSWA_REGNUM)
+       {
+         ULONGEST pswm, pswa;
+         gdb_byte buf[4];
+
+         pswa = extract_unsigned_integer (regp + regmap[S390_PSWA_REGNUM],
+                                          8, byte_order);
+         pswm = extract_unsigned_integer (regp + regmap[S390_PSWM_REGNUM],
+                                          8, byte_order);
+
+         store_unsigned_integer (buf, 4, byte_order,
+                                 (pswa & 0x7fffffff) | (pswm & 0x80000000));
+         regcache_raw_supply (regcache, regno, buf);
+         return;
+       }
+
+      if (regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
+       offset += 4;
+    }
+#endif
+
+  if (offset != -1)
+    regcache_raw_supply (regcache, regno, regp + offset);
+}
+
+static void
+s390_native_collect (const struct regcache *regcache, int regno,
+                    gdb_byte *regp, int *regmap)
+{
+  int offset = regmap[regno];
+
+#ifdef __s390x__
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  if (offset != -1 && gdbarch_ptr_bit (gdbarch) == 32)
+    {
+      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+      if (regno == S390_PSWM_REGNUM)
+       {
+         ULONGEST pswm;
+         gdb_byte buf[4];
+
+         regcache_raw_collect (regcache, regno, buf);
+         pswm = extract_unsigned_integer (buf, 4, byte_order);
+
+         /* We don't know the final addressing mode until the PSW address
+            is known, so leave it as-is.  When the PSW address is collected
+            (below), the addressing mode will be updated.  */
+         store_unsigned_integer (regp + regmap[S390_PSWM_REGNUM],
+                                 4, byte_order, pswm & 0xfff7ffff);
+         return;
+       }
+
+      if (regno == S390_PSWA_REGNUM)
+       {
+         ULONGEST pswa;
+         gdb_byte buf[4];
+
+         regcache_raw_collect (regcache, regno, buf);
+         pswa = extract_unsigned_integer (buf, 4, byte_order);
+
+         store_unsigned_integer (regp + regmap[S390_PSWA_REGNUM],
+                                 8, byte_order, pswa & 0x7fffffff);
+
+         /* Update basic addressing mode bit in PSW mask, see above.  */
+         store_unsigned_integer (regp + regmap[S390_PSWM_REGNUM] + 4,
+                                 4, byte_order, pswa & 0x80000000);
+         return;
+       }
+
+      if (regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM)
+       {
+         memset (regp + offset, 0, 4);
+         offset += 4;
+       }
+    }
 #endif
 
+  if (offset != -1)
+    regcache_raw_collect (regcache, regno, regp + offset);
+}
 
 /* Fill GDB's register array with the general-purpose register values
    in *REGP.  */
 void
 supply_gregset (struct regcache *regcache, const gregset_t *regp)
 {
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   int i;
   for (i = 0; i < S390_NUM_REGS; i++)
-    if (regmap_gregset[i] != -1)
-      regcache_raw_supply (regcache, i, 
-                          (const char *)regp + regmap_gregset[i]
-                            + SUBOFF (gdbarch, i));
+    s390_native_supply (regcache, i, (const gdb_byte *) regp, regmap_gregset);
 }
 
 /* Fill register REGNO (if it is a general-purpose register) in
@@ -85,14 +179,10 @@ supply_gregset (struct regcache *regcache, const gregset_t *regp)
 void
 fill_gregset (const struct regcache *regcache, gregset_t *regp, int regno)
 {
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   int i;
   for (i = 0; i < S390_NUM_REGS; i++)
-    if (regmap_gregset[i] != -1)
-      if (regno == -1 || regno == i)
-       regcache_raw_collect (regcache, i, 
-                             (char *)regp + regmap_gregset[i]
-                               + SUBOFF (gdbarch, i));
+    if (regno == -1 || regno == i)
+      s390_native_collect (regcache, i, (gdb_byte *) regp, regmap_gregset);
 }
 
 /* Fill GDB's register array with the floating-point register values
@@ -102,9 +192,7 @@ supply_fpregset (struct regcache *regcache, const fpregset_t *regp)
 {
   int i;
   for (i = 0; i < S390_NUM_REGS; i++)
-    if (regmap_fpregset[i] != -1)
-      regcache_raw_supply (regcache, i,
-                          (const char *)regp + regmap_fpregset[i]);
+    s390_native_supply (regcache, i, (const gdb_byte *) regp, regmap_fpregset);
 }
 
 /* Fill register REGNO (if it is a general-purpose register) in
@@ -115,10 +203,8 @@ fill_fpregset (const struct regcache *regcache, fpregset_t *regp, int regno)
 {
   int i;
   for (i = 0; i < S390_NUM_REGS; i++)
-    if (regmap_fpregset[i] != -1)
-      if (regno == -1 || regno == i)
-        regcache_raw_collect (regcache, i, 
-                             (char *)regp + regmap_fpregset[i]);
+    if (regno == -1 || regno == i)
+      s390_native_collect (regcache, i, (gdb_byte *) regp, regmap_fpregset);
 }
 
 /* Find the TID for the current inferior thread to use with ptrace.  */
index 7e36a281575243fc422502c647ac340272a2c326..1bc6fde422aa4458d49c877c06f0ea916050fb82 100644 (file)
@@ -352,8 +352,14 @@ s390_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  /* PC and CC pseudo registers need to be saved/restored in order to
-     push or pop frames.  */
+  /* We usually save/restore the whole PSW, which includes PC and CC.
+     However, some older gdbservers may not support saving/restoring
+     the whole PSW yet, and will return an XML register description
+     excluding those from the save/restore register groups.  In those
+     cases, we still need to explicitly save/restore PC and CC in order
+     to push or pop frames.  Since this doesn't hurt anything if we
+     already save/restore the whole PSW (it's just redundant), we add
+     PC and CC at this point unconditionally.  */
   if (group == save_reggroup || group == restore_reggroup)
     return regnum == tdep->pc_regnum || regnum == tdep->cc_regnum;
 
@@ -1449,6 +1455,79 @@ s390_displaced_step_fixup (struct gdbarch *gdbarch,
                        paddress (gdbarch, regcache_read_pc (regs)));
 }
 
+
+/* Helper routine to unwind pseudo registers.  */
+
+static struct value *
+s390_unwind_pseudo_register (struct frame_info *this_frame, int regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  struct type *type = register_type (gdbarch, regnum);
+
+  /* Unwind PC via PSW address.  */
+  if (regnum == tdep->pc_regnum)
+    {
+      struct value *val;
+
+      val = frame_unwind_register_value (this_frame, S390_PSWA_REGNUM);
+      if (!value_optimized_out (val))
+       {
+         LONGEST pswa = value_as_long (val);
+
+         if (TYPE_LENGTH (type) == 4)
+           return value_from_pointer (type, pswa & 0x7fffffff);
+         else
+           return value_from_pointer (type, pswa);
+       }
+    }
+
+  /* Unwind CC via PSW mask.  */
+  if (regnum == tdep->cc_regnum)
+    {
+      struct value *val;
+
+      val = frame_unwind_register_value (this_frame, S390_PSWM_REGNUM);
+      if (!value_optimized_out (val))
+       {
+         LONGEST pswm = value_as_long (val);
+
+         if (TYPE_LENGTH (type) == 4)
+           return value_from_longest (type, (pswm >> 12) & 3);
+         else
+           return value_from_longest (type, (pswm >> 44) & 3);
+       }
+    }
+
+  /* Unwind full GPRs to show at least the lower halves (as the
+     upper halves are undefined).  */
+  if (tdep->gpr_full_regnum != -1
+      && regnum >= tdep->gpr_full_regnum
+      && regnum < tdep->gpr_full_regnum + 16)
+    {
+      int reg = regnum - tdep->gpr_full_regnum;
+      struct value *val;
+
+      val = frame_unwind_register_value (this_frame, S390_R0_REGNUM + reg);
+      if (!value_optimized_out (val))
+       return value_cast (type, val);
+    }
+
+  return allocate_optimized_out_value (type);
+}
+
+static struct value *
+s390_trad_frame_prev_register (struct frame_info *this_frame,
+                              struct trad_frame_saved_reg saved_regs[],
+                              int regnum)
+{
+  if (regnum < S390_NUM_REGS)
+    return trad_frame_get_prev_register (this_frame, saved_regs, regnum);
+  else
+    return s390_unwind_pseudo_register (this_frame, regnum);
+}
+
+
 /* Normal stack frames.  */
 
 struct s390_unwind_cache {
@@ -1465,7 +1544,6 @@ s390_prologue_frame_unwind_cache (struct frame_info *this_frame,
                                  struct s390_unwind_cache *info)
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   int word_size = gdbarch_ptr_bit (gdbarch) / 8;
   struct s390_prologue_data data;
   pv_t *fp = &data.gpr[S390_FRAME_REGNUM - S390_R0_REGNUM];
@@ -1591,7 +1669,7 @@ s390_prologue_frame_unwind_cache (struct frame_info *this_frame,
       trad_frame_set_unknown (info->saved_regs, i);
 
   /* CC is always call-clobbered.  */
-  trad_frame_set_unknown (info->saved_regs, tdep->cc_regnum);
+  trad_frame_set_unknown (info->saved_regs, S390_PSWM_REGNUM);
 
   /* Record the addresses of all register spill slots the prologue parser
      has recognized.  Consider only registers defined as call-saved by the
@@ -1609,16 +1687,16 @@ s390_prologue_frame_unwind_cache (struct frame_info *this_frame,
       info->saved_regs[S390_F0_REGNUM + i].addr = cfa - data.fpr_slot[i];
 
   /* Function return will set PC to %r14.  */
-  info->saved_regs[tdep->pc_regnum] = info->saved_regs[S390_RETADDR_REGNUM];
+  info->saved_regs[S390_PSWA_REGNUM] = info->saved_regs[S390_RETADDR_REGNUM];
 
   /* In frameless functions, we unwind simply by moving the return
      address to the PC.  However, if we actually stored to the
      save area, use that -- we might only think the function frameless
      because we're in the middle of the prologue ...  */
   if (size == 0
-      && !trad_frame_addr_p (info->saved_regs, tdep->pc_regnum))
+      && !trad_frame_addr_p (info->saved_regs, S390_PSWA_REGNUM))
     {
-      info->saved_regs[tdep->pc_regnum].realreg = S390_RETADDR_REGNUM;
+      info->saved_regs[S390_PSWA_REGNUM].realreg = S390_RETADDR_REGNUM;
     }
 
   /* Another sanity check: unless this is a frameless function,
@@ -1628,7 +1706,7 @@ s390_prologue_frame_unwind_cache (struct frame_info *this_frame,
   if (size > 0)
     {
       if (!trad_frame_addr_p (info->saved_regs, S390_SP_REGNUM)
-         || !trad_frame_addr_p (info->saved_regs, tdep->pc_regnum))
+         || !trad_frame_addr_p (info->saved_regs, S390_PSWA_REGNUM))
        prev_sp = -1;
     }
 
@@ -1649,7 +1727,6 @@ s390_backchain_frame_unwind_cache (struct frame_info *this_frame,
                                   struct s390_unwind_cache *info)
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   int word_size = gdbarch_ptr_bit (gdbarch) / 8;
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   CORE_ADDR backchain;
@@ -1663,7 +1740,7 @@ s390_backchain_frame_unwind_cache (struct frame_info *this_frame,
       trad_frame_set_unknown (info->saved_regs, i);
 
   /* CC is always call-clobbered.  */
-  trad_frame_set_unknown (info->saved_regs, tdep->cc_regnum);
+  trad_frame_set_unknown (info->saved_regs, S390_PSWM_REGNUM);
 
   /* Get the backchain.  */
   reg = get_frame_register_unsigned (this_frame, S390_SP_REGNUM);
@@ -1685,7 +1762,7 @@ s390_backchain_frame_unwind_cache (struct frame_info *this_frame,
       info->saved_regs[S390_RETADDR_REGNUM].addr = backchain + 14*word_size;
 
       /* Function return will set PC to %r14.  */
-      info->saved_regs[tdep->pc_regnum]
+      info->saved_regs[S390_PSWA_REGNUM]
        = info->saved_regs[S390_RETADDR_REGNUM];
 
       /* We use the current value of the frame register as local_base,
@@ -1739,28 +1816,10 @@ s390_frame_prev_register (struct frame_info *this_frame,
                          void **this_prologue_cache, int regnum)
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   struct s390_unwind_cache *info
     = s390_frame_unwind_cache (this_frame, this_prologue_cache);
 
-  /* Unwind full GPRs to show at least the lower halves (as the
-     upper halves are undefined).  */
-  if (tdep->gpr_full_regnum != -1
-      && regnum >= tdep->gpr_full_regnum
-      && regnum < tdep->gpr_full_regnum + 16)
-    {
-      int reg = regnum - tdep->gpr_full_regnum + S390_R0_REGNUM;
-      struct value *val, *newval;
-
-      val = trad_frame_get_prev_register (this_frame, info->saved_regs, reg);
-      newval = value_cast (register_type (gdbarch, regnum), val);
-      if (value_optimized_out (val))
-       set_value_optimized_out (newval, 1);
-
-      return newval;
-    }
-
-  return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
+  return s390_trad_frame_prev_register (this_frame, info->saved_regs, regnum);
 }
 
 static const struct frame_unwind s390_frame_unwind = {
@@ -1788,7 +1847,6 @@ s390_stub_frame_unwind_cache (struct frame_info *this_frame,
                              void **this_prologue_cache)
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   int word_size = gdbarch_ptr_bit (gdbarch) / 8;
   struct s390_stub_unwind_cache *info;
   ULONGEST reg;
@@ -1801,7 +1859,7 @@ s390_stub_frame_unwind_cache (struct frame_info *this_frame,
   info->saved_regs = trad_frame_alloc_saved_regs (this_frame);
 
   /* The return address is in register %r14.  */
-  info->saved_regs[tdep->pc_regnum].realreg = S390_RETADDR_REGNUM;
+  info->saved_regs[S390_PSWA_REGNUM].realreg = S390_RETADDR_REGNUM;
 
   /* Retrieve stack pointer and determine our frame base.  */
   reg = get_frame_register_unsigned (this_frame, S390_SP_REGNUM);
@@ -1826,7 +1884,7 @@ s390_stub_frame_prev_register (struct frame_info *this_frame,
 {
   struct s390_stub_unwind_cache *info
     = s390_stub_frame_unwind_cache (this_frame, this_prologue_cache);
-  return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
+  return s390_trad_frame_prev_register (this_frame, info->saved_regs, regnum);
 }
 
 static int
@@ -1875,7 +1933,6 @@ s390_sigtramp_frame_unwind_cache (struct frame_info *this_frame,
   struct s390_sigtramp_unwind_cache *info;
   ULONGEST this_sp, prev_sp;
   CORE_ADDR next_ra, next_cfa, sigreg_ptr, sigreg_high_off;
-  ULONGEST pswm;
   int i;
 
   if (*this_prologue_cache)
@@ -1928,16 +1985,6 @@ s390_sigtramp_frame_unwind_cache (struct frame_info *this_frame,
   info->saved_regs[S390_PSWA_REGNUM].addr = sigreg_ptr;
   sigreg_ptr += word_size;
 
-  /* Point PC to PSWA as well.  */
-  info->saved_regs[tdep->pc_regnum] = info->saved_regs[S390_PSWA_REGNUM];
-
-  /* Extract CC from PSWM.  */
-  pswm = read_memory_unsigned_integer (
-                       info->saved_regs[S390_PSWM_REGNUM].addr,
-                       word_size, byte_order);
-  trad_frame_set_value (info->saved_regs, tdep->cc_regnum,
-                       (pswm >> (8 * word_size - 20)) & 3);
-
   /* Then the GPRs.  */
   for (i = 0; i < 16; i++)
     {
@@ -1972,22 +2019,6 @@ s390_sigtramp_frame_unwind_cache (struct frame_info *this_frame,
        sigreg_ptr += 4;
       }
 
-  /* Provide read-only copies of the full registers.  */
-  if (tdep->gpr_full_regnum != -1)
-    for (i = 0; i < 16; i++)
-      {
-       ULONGEST low, high;
-       low = read_memory_unsigned_integer (
-                       info->saved_regs[S390_R0_REGNUM + i].addr,
-                       4, byte_order);
-       high = read_memory_unsigned_integer (
-                       info->saved_regs[S390_R0_UPPER_REGNUM + i].addr,
-                       4, byte_order);
-       
-       trad_frame_set_value (info->saved_regs, tdep->gpr_full_regnum + i,
-                             (high << 32) | low);
-      }
-
   /* Restore the previous frame's SP.  */
   prev_sp = read_memory_unsigned_integer (
                        info->saved_regs[S390_SP_REGNUM].addr,
@@ -2015,7 +2046,7 @@ s390_sigtramp_frame_prev_register (struct frame_info *this_frame,
 {
   struct s390_sigtramp_unwind_cache *info
     = s390_sigtramp_frame_unwind_cache (this_frame, this_prologue_cache);
-  return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
+  return s390_trad_frame_prev_register (this_frame, info->saved_regs, regnum);
 }
 
 static int
@@ -2098,17 +2129,7 @@ static struct value *
 s390_dwarf2_prev_register (struct frame_info *this_frame, void **this_cache,
                           int regnum)
 {
-  struct gdbarch *gdbarch = get_frame_arch (this_frame);
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-  int reg = regnum - tdep->gpr_full_regnum;
-  struct value *val, *newval;
-
-  val = frame_unwind_register_value (this_frame, S390_R0_REGNUM + reg);
-  newval = value_cast (register_type (gdbarch, regnum), val);
-  if (value_optimized_out (val))
-    set_value_optimized_out (newval, 1);
-
-  return newval;
+  return s390_unwind_pseudo_register (this_frame, regnum);
 }
 
 static void
@@ -2118,9 +2139,17 @@ s390_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
+  /* The condition code (and thus PSW mask) is call-clobbered.  */
+  if (regnum == S390_PSWM_REGNUM)
+    reg->how = DWARF2_FRAME_REG_UNDEFINED;
+
+  /* The PSW address unwinds to the return address.  */
+  else if (regnum == S390_PSWA_REGNUM)
+    reg->how = DWARF2_FRAME_REG_RA;
+
   /* Fixed registers are call-saved or call-clobbered
      depending on the ABI in use.  */
-  if (regnum >= 0 && regnum < S390_NUM_REGS)
+  else if (regnum < S390_NUM_REGS)
     {
       if (s390_register_call_saved (gdbarch, regnum))
        reg->how = DWARF2_FRAME_REG_SAME_VALUE;
@@ -2128,19 +2157,8 @@ s390_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
        reg->how = DWARF2_FRAME_REG_UNDEFINED;
     }
 
-  /* The CC pseudo register is call-clobbered.  */
-  else if (regnum == tdep->cc_regnum)
-    reg->how = DWARF2_FRAME_REG_UNDEFINED;
-
-  /* The PC register unwinds to the return address.  */
-  else if (regnum == tdep->pc_regnum)
-    reg->how = DWARF2_FRAME_REG_RA;
-
-  /* We install a special function to unwind full GPRs to show at
-     least the lower halves (as the upper halves are undefined).  */
-  else if (tdep->gpr_full_regnum != -1
-          && regnum >= tdep->gpr_full_regnum
-          && regnum < tdep->gpr_full_regnum + 16)
+  /* We install a special function to unwind pseudos.  */
+  else
     {
       reg->how = DWARF2_FRAME_REG_FN;
       reg->loc.fn = s390_dwarf2_prev_register;