diff options
author | Ulrich Weigand <uweigand@de.ibm.com> | 2011-11-30 16:06:55 +0000 |
---|---|---|
committer | Ulrich Weigand <uweigand@de.ibm.com> | 2011-11-30 16:06:55 +0000 |
commit | d6db1fabccd61cdc0527cf7c701ae5cf7f277281 (patch) | |
tree | 1ee15269e26f8d23a2a607df2b02f2aff461bbad /gdb | |
parent | 1dd635acb8bfcf517fae1d3e21d312828efdb2b1 (diff) | |
download | gdb-d6db1fabccd61cdc0527cf7c701ae5cf7f277281.zip gdb-d6db1fabccd61cdc0527cf7c701ae5cf7f277281.tar.gz gdb-d6db1fabccd61cdc0527cf7c701ae5cf7f277281.tar.bz2 |
ChangeLog:
* 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.
Diffstat (limited to 'gdb')
-rw-r--r-- | gdb/ChangeLog | 28 | ||||
-rw-r--r-- | gdb/features/s390-core32.xml | 4 | ||||
-rw-r--r-- | gdb/features/s390-core64.xml | 4 | ||||
-rw-r--r-- | gdb/features/s390-linux32.c | 5 | ||||
-rw-r--r-- | gdb/features/s390-linux64.c | 5 | ||||
-rw-r--r-- | gdb/features/s390x-core64.xml | 4 | ||||
-rw-r--r-- | gdb/features/s390x-linux64.c | 5 | ||||
-rw-r--r-- | gdb/gdbserver/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/gdbserver/linux-s390-low.c | 74 | ||||
-rw-r--r-- | gdb/s390-nat.c | 134 | ||||
-rw-r--r-- | gdb/s390-tdep.c | 190 |
11 files changed, 319 insertions, 142 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 49f2945..dcaf777 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,33 @@ 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. 2011-11-30 Ulrich Weigand <uweigand@de.ibm.com> diff --git a/gdb/features/s390-core32.xml b/gdb/features/s390-core32.xml index 3c0937a..989e555 100644 --- a/gdb/features/s390-core32.xml +++ b/gdb/features/s390-core32.xml @@ -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"/> diff --git a/gdb/features/s390-core64.xml b/gdb/features/s390-core64.xml index 7abe38d..d5998c9 100644 --- a/gdb/features/s390-core64.xml +++ b/gdb/features/s390-core64.xml @@ -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"/> diff --git a/gdb/features/s390-linux32.c b/gdb/features/s390-linux32.c index 0ff3868..0e28c72 100644 --- a/gdb/features/s390-linux32.c +++ b/gdb/features/s390-linux32.c @@ -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"); diff --git a/gdb/features/s390-linux64.c b/gdb/features/s390-linux64.c index 1e39fc3..e7acfe2 100644 --- a/gdb/features/s390-linux64.c +++ b/gdb/features/s390-linux64.c @@ -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"); diff --git a/gdb/features/s390x-core64.xml b/gdb/features/s390x-core64.xml index eca8246..2f01903 100644 --- a/gdb/features/s390x-core64.xml +++ b/gdb/features/s390x-core64.xml @@ -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"/> diff --git a/gdb/features/s390x-linux64.c b/gdb/features/s390x-linux64.c index 91d2da9..06a9339 100644 --- a/gdb/features/s390x-linux64.c +++ b/gdb/features/s390x-linux64.c @@ -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"); diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index f383edc..464d9df 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -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. diff --git a/gdb/gdbserver/linux-s390-low.c b/gdb/gdbserver/linux-s390-low.c index 5c38e43..898b757 100644 --- a/gdb/gdbserver/linux-s390-low.c +++ b/gdb/gdbserver/linux-s390-low.c @@ -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 { diff --git a/gdb/s390-nat.c b/gdb/s390-nat.c index 5bc88a9..c1eec1c 100644 --- a/gdb/s390-nat.c +++ b/gdb/s390-nat.c @@ -55,28 +55,122 @@ /* 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. */ diff --git a/gdb/s390-tdep.c b/gdb/s390-tdep.c index 7e36a28..1bc6fde 100644 --- a/gdb/s390-tdep.c +++ b/gdb/s390-tdep.c @@ -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; |