]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/s390-tdep.c
Switch the license of all .c files to GPLv3.
[thirdparty/binutils-gdb.git] / gdb / s390-tdep.c
index 2499c3c445519eb81acfb95ba8fc7004d28d18ec..a5b0de18b8eb55f6cc0048df41742173aadab010 100644 (file)
@@ -1,6 +1,7 @@
 /* Target-dependent code for GDB, the GNU debugger.
 
-   Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
 
    Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
    for IBM Deutschland Entwicklung GmbH, IBM Corporation.
@@ -9,7 +10,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -18,9 +19,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "arch-utils.h"
 #include "gdbcore.h"
 #include "gdbcmd.h"
 #include "objfiles.h"
-#include "tm.h"
-#include "../bfd/bfd.h"
 #include "floatformat.h"
 #include "regcache.h"
 #include "trad-frame.h"
 #include "frame-base.h"
 #include "frame-unwind.h"
+#include "dwarf2-frame.h"
 #include "reggroups.h"
 #include "regset.h"
 #include "value.h"
 #include "gdb_assert.h"
 #include "dis-asm.h"
-#include "solib-svr4.h"         /* For struct link_map_offsets.  */
+#include "solib-svr4.h"
+#include "prologue-value.h"
 
 #include "s390-tdep.h"
 
@@ -64,97 +63,54 @@ struct gdbarch_tdep
 };
 
 
-/* Register information.  */
-
-struct s390_register_info
-{
-  char *name;
-  struct type **type;
-};
-
-static struct s390_register_info s390_register_info[S390_NUM_TOTAL_REGS] = 
-{
-  /* Program Status Word.  */
-  { "pswm", &builtin_type_long },
-  { "pswa", &builtin_type_long },
-
-  /* General Purpose Registers.  */
-  { "r0", &builtin_type_long },
-  { "r1", &builtin_type_long },
-  { "r2", &builtin_type_long },
-  { "r3", &builtin_type_long },
-  { "r4", &builtin_type_long },
-  { "r5", &builtin_type_long },
-  { "r6", &builtin_type_long },
-  { "r7", &builtin_type_long },
-  { "r8", &builtin_type_long },
-  { "r9", &builtin_type_long },
-  { "r10", &builtin_type_long },
-  { "r11", &builtin_type_long },
-  { "r12", &builtin_type_long },
-  { "r13", &builtin_type_long },
-  { "r14", &builtin_type_long },
-  { "r15", &builtin_type_long },
-
-  /* Access Registers.  */
-  { "acr0", &builtin_type_int },
-  { "acr1", &builtin_type_int },
-  { "acr2", &builtin_type_int },
-  { "acr3", &builtin_type_int },
-  { "acr4", &builtin_type_int },
-  { "acr5", &builtin_type_int },
-  { "acr6", &builtin_type_int },
-  { "acr7", &builtin_type_int },
-  { "acr8", &builtin_type_int },
-  { "acr9", &builtin_type_int },
-  { "acr10", &builtin_type_int },
-  { "acr11", &builtin_type_int },
-  { "acr12", &builtin_type_int },
-  { "acr13", &builtin_type_int },
-  { "acr14", &builtin_type_int },
-  { "acr15", &builtin_type_int },
-
-  /* Floating Point Control Word.  */
-  { "fpc", &builtin_type_int },
-
-  /* Floating Point Registers.  */
-  { "f0", &builtin_type_double },
-  { "f1", &builtin_type_double },
-  { "f2", &builtin_type_double },
-  { "f3", &builtin_type_double },
-  { "f4", &builtin_type_double },
-  { "f5", &builtin_type_double },
-  { "f6", &builtin_type_double },
-  { "f7", &builtin_type_double },
-  { "f8", &builtin_type_double },
-  { "f9", &builtin_type_double },
-  { "f10", &builtin_type_double },
-  { "f11", &builtin_type_double },
-  { "f12", &builtin_type_double },
-  { "f13", &builtin_type_double },
-  { "f14", &builtin_type_double },
-  { "f15", &builtin_type_double },
-
-  /* Pseudo registers.  */
-  { "pc", &builtin_type_void_func_ptr },
-  { "cc", &builtin_type_int },
-};
-
 /* Return the name of register REGNUM.  */
 static const char *
 s390_register_name (int regnum)
 {
+  static const char *register_names[S390_NUM_TOTAL_REGS] =
+    {
+      /* Program Status Word.  */
+      "pswm", "pswa",
+      /* General Purpose Registers.  */
+      "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+      "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+      /* Access Registers.  */
+      "acr0", "acr1", "acr2", "acr3", "acr4", "acr5", "acr6", "acr7",
+      "acr8", "acr9", "acr10", "acr11", "acr12", "acr13", "acr14", "acr15",
+      /* Floating Point Control Word.  */
+      "fpc",
+      /* Floating Point Registers.  */
+      "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+      "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+      /* Pseudo registers.  */
+      "pc", "cc",
+    };
+
   gdb_assert (regnum >= 0 && regnum < S390_NUM_TOTAL_REGS);
-  return s390_register_info[regnum].name;
+  return register_names[regnum];
 }
 
 /* Return the GDB type object for the "standard" data type of data in
-   register REGNUM. */
+   register REGNUM.  */
 static struct type *
 s390_register_type (struct gdbarch *gdbarch, int regnum)
 {
-  gdb_assert (regnum >= 0 && regnum < S390_NUM_TOTAL_REGS);
-  return *s390_register_info[regnum].type;
+  if (regnum == S390_PSWM_REGNUM || regnum == S390_PSWA_REGNUM)
+    return builtin_type_long;
+  if (regnum >= S390_R0_REGNUM && regnum <= S390_R15_REGNUM)
+    return builtin_type_long;
+  if (regnum >= S390_A0_REGNUM && regnum <= S390_A15_REGNUM)
+    return builtin_type_int;
+  if (regnum == S390_FPC_REGNUM)
+    return builtin_type_int;
+  if (regnum >= S390_F0_REGNUM && regnum <= S390_F15_REGNUM)
+    return builtin_type_double;
+  if (regnum == S390_PC_REGNUM)
+    return builtin_type_void_func_ptr;
+  if (regnum == S390_CC_REGNUM)
+    return builtin_type_int;
+
+  internal_error (__FILE__, __LINE__, _("invalid regnum"));
 }
 
 /* DWARF Register Mapping.  */
@@ -195,11 +151,11 @@ s390_dwarf_reg_to_regnum (int reg)
 {
   int regnum = -1;
 
-  if (reg >= 0 || reg < ARRAY_SIZE (s390_dwarf_regmap))
+  if (reg >= 0 && reg < ARRAY_SIZE (s390_dwarf_regmap))
     regnum = s390_dwarf_regmap[reg];
 
   if (regnum == -1)
-    warning ("Unmapped DWARF Register #%d encountered\n", reg);
+    warning (_("Unmapped DWARF Register #%d encountered."), reg);
 
   return regnum;
 }
@@ -208,7 +164,7 @@ s390_dwarf_reg_to_regnum (int reg)
 
 static void
 s390_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
-                          int regnum, void *buf)
+                          int regnum, gdb_byte *buf)
 {
   ULONGEST val;
 
@@ -225,13 +181,13 @@ s390_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
       break;
 
     default:
-      internal_error (__FILE__, __LINE__, "invalid regnum");
+      internal_error (__FILE__, __LINE__, _("invalid regnum"));
     }
 }
 
 static void
 s390_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
-                           int regnum, const void *buf)
+                           int regnum, const gdb_byte *buf)
 {
   ULONGEST val, psw;
 
@@ -252,13 +208,13 @@ s390_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
       break;
 
     default:
-      internal_error (__FILE__, __LINE__, "invalid regnum");
+      internal_error (__FILE__, __LINE__, _("invalid regnum"));
     }
 }
 
 static void
 s390x_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
-                           int regnum, void *buf)
+                           int regnum, gdb_byte *buf)
 {
   ULONGEST val;
 
@@ -274,13 +230,13 @@ s390x_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
       break;
 
     default:
-      internal_error (__FILE__, __LINE__, "invalid regnum");
+      internal_error (__FILE__, __LINE__, _("invalid regnum"));
     }
 }
 
 static void
 s390x_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
-                            int regnum, const void *buf)
+                            int regnum, const gdb_byte *buf)
 {
   ULONGEST val, psw;
 
@@ -298,43 +254,24 @@ s390x_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
       break;
 
     default:
-      internal_error (__FILE__, __LINE__, "invalid regnum");
+      internal_error (__FILE__, __LINE__, _("invalid regnum"));
     }
 }
 
 /* 'float' values are stored in the upper half of floating-point
    registers, even though we are otherwise a big-endian platform.  */
 
-static int
-s390_convert_register_p (int regno, struct type *type)
-{
-  return (regno >= S390_F0_REGNUM && regno <= S390_F15_REGNUM)
-        && TYPE_LENGTH (type) < 8;
-}
-
-static void
-s390_register_to_value (struct frame_info *frame, int regnum,
-                        struct type *valtype, void *out)
+static struct value *
+s390_value_from_register (struct type *type, int regnum,
+                         struct frame_info *frame)
 {
-  char in[8];
-  int len = TYPE_LENGTH (valtype);
-  gdb_assert (len < 8);
-
-  get_frame_register (frame, regnum, in);
-  memcpy (out, in, len);
-}
+  struct value *value = default_value_from_register (type, regnum, frame);
+  int len = TYPE_LENGTH (type);
 
-static void
-s390_value_to_register (struct frame_info *frame, int regnum,
-                        struct type *valtype, const void *in)
-{
-  char out[8];
-  int len = TYPE_LENGTH (valtype);
-  gdb_assert (len < 8);
+  if (regnum >= S390_F0_REGNUM && regnum <= S390_F15_REGNUM && len < 8)
+    set_value_offset (value, 0);
 
-  memset (out, 0, 8);
-  memcpy (out, in, len);
-  put_frame_register (frame, regnum, out);
+  return value;
 }
 
 /* Register groups.  */
@@ -443,19 +380,41 @@ s390_supply_regset (const struct regset *regset, struct regcache *regcache,
     }
 }
 
+/* Collect register REGNUM from the register cache REGCACHE and store
+   it in the buffer specified by REGS and LEN as described by the
+   general-purpose register set REGSET.  If REGNUM is -1, do this for
+   all registers in REGSET.  */
+static void
+s390_collect_regset (const struct regset *regset,
+                    const struct regcache *regcache,
+                    int regnum, void *regs, size_t len)
+{
+  const int *offset = regset->descr;
+  int i;
+
+  for (i = 0; i < S390_NUM_REGS; i++)
+    {
+      if ((regnum == i || regnum == -1) && offset[i] != -1)
+       regcache_raw_collect (regcache, i, (char *)regs + offset[i]);
+    }
+}
+
 static const struct regset s390_gregset = {
   s390_regmap_gregset, 
-  s390_supply_regset
+  s390_supply_regset,
+  s390_collect_regset
 };
 
 static const struct regset s390x_gregset = {
   s390x_regmap_gregset, 
-  s390_supply_regset
+  s390_supply_regset,
+  s390_collect_regset
 };
 
 static const struct regset s390_fpregset = {
   s390_regmap_fpregset, 
-  s390_supply_regset
+  s390_supply_regset,
+  s390_collect_regset
 };
 
 /* Return the appropriate register set for the core section identified
@@ -476,390 +435,6 @@ s390_regset_from_core_section (struct gdbarch *gdbarch,
 }
 
 
-/* Prologue analysis.  */
-
-/* When we analyze a prologue, we're really doing 'abstract
-   interpretation' or 'pseudo-evaluation': running the function's code
-   in simulation, but using conservative approximations of the values
-   it would have when it actually runs.  For example, if our function
-   starts with the instruction:
-
-      ahi r1, 42     # add halfword immediate 42 to r1
-
-   we don't know exactly what value will be in r1 after executing this
-   instruction, but we do know it'll be 42 greater than its original
-   value.
-
-   If we then see an instruction like:
-
-      ahi r1, 22     # add halfword immediate 22 to r1
-
-   we still don't know what r1's value is, but again, we can say it is
-   now 64 greater than its original value.
-
-   If the next instruction were:
-
-      lr r2, r1      # set r2 to r1's value
-
-   then we can say that r2's value is now the original value of r1
-   plus 64.  And so on.
-
-   Of course, this can only go so far before it gets unreasonable.  If
-   we wanted to be able to say anything about the value of r1 after
-   the instruction:
-
-      xr r1, r3      # exclusive-or r1 and r3, place result in r1
-
-   then things would get pretty complex.  But remember, we're just
-   doing a conservative approximation; if exclusive-or instructions
-   aren't relevant to prologues, we can just say r1's value is now
-   'unknown'.  We can ignore things that are too complex, if that loss
-   of information is acceptable for our application.
-
-   Once you've reached an instruction that you don't know how to
-   simulate, you stop.  Now you examine the state of the registers and
-   stack slots you've kept track of.  For example:
-
-   - To see how large your stack frame is, just check the value of sp;
-     if it's the original value of sp minus a constant, then that
-     constant is the stack frame's size.  If the sp's value has been
-     marked as 'unknown', then that means the prologue has done
-     something too complex for us to track, and we don't know the
-     frame size.
-
-   - To see whether we've saved the SP in the current frame's back
-     chain slot, we just check whether the current value of the back
-     chain stack slot is the original value of the sp.
-
-   Sure, this takes some work.  But prologue analyzers aren't
-   quick-and-simple pattern patching to recognize a few fixed prologue
-   forms any more; they're big, hairy functions.  Along with inferior
-   function calls, prologue analysis accounts for a substantial
-   portion of the time needed to stabilize a GDB port.  So I think
-   it's worthwhile to look for an approach that will be easier to
-   understand and maintain.  In the approach used here:
-
-   - It's easier to see that the analyzer is correct: you just see
-     whether the analyzer properly (albiet conservatively) simulates
-     the effect of each instruction.
-
-   - It's easier to extend the analyzer: you can add support for new
-     instructions, and know that you haven't broken anything that
-     wasn't already broken before.
-
-   - It's orthogonal: to gather new information, you don't need to
-     complicate the code for each instruction.  As long as your domain
-     of conservative values is already detailed enough to tell you
-     what you need, then all the existing instruction simulations are
-     already gathering the right data for you.
-
-   A 'struct prologue_value' is a conservative approximation of the
-   real value the register or stack slot will have.  */
-
-struct prologue_value {
-
-  /* What sort of value is this?  This determines the interpretation
-     of subsequent fields.  */
-  enum {
-
-    /* We don't know anything about the value.  This is also used for
-       values we could have kept track of, when doing so would have
-       been too complex and we don't want to bother.  The bottom of
-       our lattice.  */
-    pv_unknown,
-
-    /* A known constant.  K is its value.  */
-    pv_constant,
-
-    /* The value that register REG originally had *UPON ENTRY TO THE
-       FUNCTION*, plus K.  If K is zero, this means, obviously, just
-       the value REG had upon entry to the function.  REG is a GDB
-       register number.  Before we start interpreting, we initialize
-       every register R to { pv_register, R, 0 }.  */
-    pv_register,
-
-  } kind;
-
-  /* The meanings of the following fields depend on 'kind'; see the
-     comments for the specific 'kind' values.  */
-  int reg;
-  CORE_ADDR k;
-};
-
-
-/* Set V to be unknown.  */
-static void
-pv_set_to_unknown (struct prologue_value *v)
-{
-  v->kind = pv_unknown;
-}
-
-
-/* Set V to the constant K.  */
-static void
-pv_set_to_constant (struct prologue_value *v, CORE_ADDR k)
-{
-  v->kind = pv_constant;
-  v->k = k;
-}
-
-
-/* Set V to the original value of register REG, plus K.  */
-static void
-pv_set_to_register (struct prologue_value *v, int reg, CORE_ADDR k)
-{
-  v->kind = pv_register;
-  v->reg = reg;
-  v->k = k;
-}
-
-
-/* If one of *A and *B is a constant, and the other isn't, swap the
-   pointers as necessary to ensure that *B points to the constant.
-   This can reduce the number of cases we need to analyze in the
-   functions below.  */
-static void
-pv_constant_last (struct prologue_value **a,
-                  struct prologue_value **b)
-{
-  if ((*a)->kind == pv_constant
-      && (*b)->kind != pv_constant)
-    {
-      struct prologue_value *temp = *a;
-      *a = *b;
-      *b = temp;
-    }
-}
-
-
-/* Set SUM to the sum of A and B.  SUM, A, and B may point to the same
-   'struct prologue_value' object.  */
-static void
-pv_add (struct prologue_value *sum,
-        struct prologue_value *a,
-        struct prologue_value *b)
-{
-  pv_constant_last (&a, &b);
-
-  /* We can handle adding constants to registers, and other constants.  */
-  if (b->kind == pv_constant
-      && (a->kind == pv_register
-          || a->kind == pv_constant))
-    {
-      sum->kind = a->kind;
-      sum->reg = a->reg;    /* not meaningful if a is pv_constant, but
-                               harmless */
-      sum->k = a->k + b->k;
-    }
-
-  /* Anything else we don't know how to add.  We don't have a
-     representation for, say, the sum of two registers, or a multiple
-     of a register's value (adding a register to itself).  */
-  else
-    sum->kind = pv_unknown;
-}
-
-
-/* Add the constant K to V.  */
-static void
-pv_add_constant (struct prologue_value *v, CORE_ADDR k)
-{
-  struct prologue_value pv_k;
-
-  /* Rather than thinking of all the cases we can and can't handle,
-     we'll just let pv_add take care of that for us.  */
-  pv_set_to_constant (&pv_k, k);
-  pv_add (v, v, &pv_k);
-}
-
-
-/* Subtract B from A, and put the result in DIFF.
-
-   This isn't quite the same as negating B and adding it to A, since
-   we don't have a representation for the negation of anything but a
-   constant.  For example, we can't negate { pv_register, R1, 10 },
-   but we do know that { pv_register, R1, 10 } minus { pv_register,
-   R1, 5 } is { pv_constant, <ignored>, 5 }.
-
-   This means, for example, that we can subtract two stack addresses;
-   they're both relative to the original SP.  Since the frame pointer
-   is set based on the SP, its value will be the original SP plus some
-   constant (probably zero), so we can use its value just fine.  */
-static void
-pv_subtract (struct prologue_value *diff,
-             struct prologue_value *a,
-             struct prologue_value *b)
-{
-  pv_constant_last (&a, &b);
-
-  /* We can subtract a constant from another constant, or from a
-     register.  */
-  if (b->kind == pv_constant
-      && (a->kind == pv_register
-          || a->kind == pv_constant))
-    {
-      diff->kind = a->kind;
-      diff->reg = a->reg;    /* not always meaningful, but harmless */
-      diff->k = a->k - b->k;
-    }
-
-  /* We can subtract a register from itself, yielding a constant.  */
-  else if (a->kind == pv_register
-           && b->kind == pv_register
-           && a->reg == b->reg)
-    {
-      diff->kind = pv_constant;
-      diff->k = a->k - b->k;
-    }
-
-  /* We don't know how to subtract anything else.  */
-  else
-    diff->kind = pv_unknown;
-}
-
-
-/* Set AND to the logical and of A and B.  */
-static void
-pv_logical_and (struct prologue_value *and,
-                struct prologue_value *a,
-                struct prologue_value *b)
-{
-  pv_constant_last (&a, &b);
-
-  /* We can 'and' two constants.  */
-  if (a->kind == pv_constant
-      && b->kind == pv_constant)
-    {
-      and->kind = pv_constant;
-      and->k = a->k & b->k;
-    }
-
-  /* We can 'and' anything with the constant zero.  */
-  else if (b->kind == pv_constant
-           && b->k == 0)
-    {
-      and->kind = pv_constant;
-      and->k = 0;
-    }
-  
-  /* We can 'and' anything with ~0.  */
-  else if (b->kind == pv_constant
-           && b->k == ~ (CORE_ADDR) 0)
-    *and = *a;
-
-  /* We can 'and' a register with itself.  */
-  else if (a->kind == pv_register
-           && b->kind == pv_register
-           && a->reg == b->reg
-           && a->k == b->k)
-    *and = *a;
-
-  /* Otherwise, we don't know.  */
-  else
-    pv_set_to_unknown (and);
-}
-
-
-/* Return non-zero iff A and B are identical expressions.
-
-   This is not the same as asking if the two values are equal; the
-   result of such a comparison would have to be a pv_boolean, and
-   asking whether two 'unknown' values were equal would give you
-   pv_maybe.  Same for comparing, say, { pv_register, R1, 0 } and {
-   pv_register, R2, 0}.  Instead, this is asking whether the two
-   representations are the same.  */
-static int
-pv_is_identical (struct prologue_value *a,
-                 struct prologue_value *b)
-{
-  if (a->kind != b->kind)
-    return 0;
-
-  switch (a->kind)
-    {
-    case pv_unknown:
-      return 1;
-    case pv_constant:
-      return (a->k == b->k);
-    case pv_register:
-      return (a->reg == b->reg && a->k == b->k);
-    default:
-      gdb_assert (0);
-    }
-}
-
-
-/* Return non-zero if A is the original value of register number R
-   plus K, zero otherwise.  */
-static int
-pv_is_register (struct prologue_value *a, int r, CORE_ADDR k)
-{
-  return (a->kind == pv_register
-          && a->reg == r
-          && a->k == k);
-}
-
-
-/* A prologue-value-esque boolean type, including "maybe", when we
-   can't figure out whether something is true or not.  */
-enum pv_boolean {
-  pv_maybe,
-  pv_definite_yes,
-  pv_definite_no,
-};
-
-
-/* Decide whether a reference to SIZE bytes at ADDR refers exactly to
-   an element of an array.  The array starts at ARRAY_ADDR, and has
-   ARRAY_LEN values of ELT_SIZE bytes each.  If ADDR definitely does
-   refer to an array element, set *I to the index of the referenced
-   element in the array, and return pv_definite_yes.  If it definitely
-   doesn't, return pv_definite_no.  If we can't tell, return pv_maybe.
-
-   If the reference does touch the array, but doesn't fall exactly on
-   an element boundary, or doesn't refer to the whole element, return
-   pv_maybe.  */
-static enum pv_boolean
-pv_is_array_ref (struct prologue_value *addr,
-                 CORE_ADDR size,
-                 struct prologue_value *array_addr,
-                 CORE_ADDR array_len, 
-                 CORE_ADDR elt_size,
-                 int *i)
-{
-  struct prologue_value offset;
-
-  /* Note that, since ->k is a CORE_ADDR, and CORE_ADDR is unsigned,
-     if addr is *before* the start of the array, then this isn't going
-     to be negative...  */
-  pv_subtract (&offset, addr, array_addr);
-
-  if (offset.kind == pv_constant)
-    {
-      /* This is a rather odd test.  We want to know if the SIZE bytes
-         at ADDR don't overlap the array at all, so you'd expect it to
-         be an || expression: "if we're completely before || we're
-         completely after".  But with unsigned arithmetic, things are
-         different: since it's a number circle, not a number line, the
-         right values for offset.k are actually one contiguous range.  */
-      if (offset.k <= -size
-          && offset.k >= array_len * elt_size)
-        return pv_definite_no;
-      else if (offset.k % elt_size != 0
-               || size != elt_size)
-        return pv_maybe;
-      else
-        {
-          *i = offset.k / elt_size;
-          return pv_definite_yes;
-        }
-    }
-  else
-    return pv_maybe;
-}
-
-
-
 /* Decoding S/390 instructions.  */
 
 /* Named opcode values for the S/390 instructions we recognize.  Some
@@ -869,6 +444,7 @@ enum
   {
     op1_lhi  = 0xa7,   op2_lhi  = 0x08,
     op1_lghi = 0xa7,   op2_lghi = 0x09,
+    op1_lgfi = 0xc0,   op2_lgfi = 0x01,
     op_lr    = 0x18,
     op_lgr   = 0xb904,
     op_l     = 0x58,
@@ -886,11 +462,17 @@ enum
     op1_stmg = 0xeb,   op2_stmg = 0x24,
     op1_aghi = 0xa7,   op2_aghi = 0x0b,
     op1_ahi  = 0xa7,   op2_ahi  = 0x0a,
+    op1_agfi = 0xc2,   op2_agfi = 0x08,
+    op1_afi  = 0xc2,   op2_afi  = 0x09,
+    op1_algfi= 0xc2,   op2_algfi= 0x0a,
+    op1_alfi = 0xc2,   op2_alfi = 0x0b,
     op_ar    = 0x1a,
     op_agr   = 0xb908,
     op_a     = 0x5a,
     op1_ay   = 0xe3,   op2_ay   = 0x5a,
     op1_ag   = 0xe3,   op2_ag   = 0x08,
+    op1_slgfi= 0xc2,   op2_slgfi= 0x04,
+    op1_slfi = 0xc2,   op2_slfi = 0x05,
     op_sr    = 0x1b,
     op_sgr   = 0xb909,
     op_s     = 0x5b,
@@ -1085,197 +667,165 @@ is_rxy (bfd_byte *insn, int op1, int op2,
 }
 
 
-/* Set ADDR to the effective address for an X-style instruction, like:
-
-        L R1, D2(X2, B2)
-
-   Here, X2 and B2 are registers, and D2 is a signed 20-bit
-   constant; the effective address is the sum of all three.  If either
-   X2 or B2 are zero, then it doesn't contribute to the sum --- this
-   means that r0 can't be used as either X2 or B2.
-
-   GPR is an array of general register values, indexed by GPR number,
-   not GDB register number.  */
-static void
-compute_x_addr (struct prologue_value *addr, 
-                struct prologue_value *gpr,
-                int d2, unsigned int x2, unsigned int b2)
-{
-  /* We can't just add stuff directly in addr; it might alias some of
-     the registers we need to read.  */
-  struct prologue_value result;
-
-  pv_set_to_constant (&result, d2);
-  if (x2)
-    pv_add (&result, &result, &gpr[x2]);
-  if (b2)
-    pv_add (&result, &result, &gpr[b2]);
-
-  *addr = result;
-}
-
+/* Prologue analysis.  */
 
-/* The number of GPR and FPR spill slots in an S/390 stack frame.  We
-   track general-purpose registers r2 -- r15, and floating-point
-   registers f0, f2, f4, and f6.  */
-#define S390_NUM_SPILL_SLOTS (14 + 4)
 #define S390_NUM_GPRS 16
 #define S390_NUM_FPRS 16
 
 struct s390_prologue_data {
 
+  /* The stack.  */
+  struct pv_area *stack;
+
   /* The size of a GPR or FPR.  */
   int gpr_size;
   int fpr_size;
 
   /* The general-purpose registers.  */
-  struct prologue_value gpr[S390_NUM_GPRS];
+  pv_t gpr[S390_NUM_GPRS];
 
   /* The floating-point registers.  */
-  struct prologue_value fpr[S390_NUM_FPRS];
-
-  /* The register spill stack slots in the caller's frame ---
-     general-purpose registers r2 through r15, and floating-point
-     registers.  spill[i] is where gpr i+2 gets spilled;
-     spill[(14, 15, 16, 17)] is where (f0, f2, f4, f6) get spilled.  */
-  struct prologue_value spill[S390_NUM_SPILL_SLOTS];
-
-  /* The value of the back chain slot.  This is only valid if the stack
-     pointer is known to be less than its original value --- that is,
-     if we have indeed allocated space on the stack.  */
-  struct prologue_value back_chain;
-};
+  pv_t fpr[S390_NUM_FPRS];
 
+  /* The offset relative to the CFA where the incoming GPR N was saved
+     by the function prologue.  0 if not saved or unknown.  */
+  int gpr_slot[S390_NUM_GPRS];
 
-/* If the SIZE bytes at ADDR are a stack slot we're actually tracking,
-   return pv_definite_yes and set *STACK to point to the slot.  If
-   we're sure that they are not any of our stack slots, then return
-   pv_definite_no.  Otherwise, return pv_maybe.
+  /* Likewise for FPRs.  */
+  int fpr_slot[S390_NUM_FPRS];
 
-   DATA describes our current state (registers and stack slots).  */
-static enum pv_boolean
-s390_on_stack (struct prologue_value *addr,
-               CORE_ADDR size,
-              struct s390_prologue_data *data,
-               struct prologue_value **stack)
-{
-  struct prologue_value gpr_spill_addr;
-  struct prologue_value fpr_spill_addr;
-  struct prologue_value back_chain_addr;  
-  int i;
-  enum pv_boolean b;
+  /* Nonzero if the backchain was saved.  This is assumed to be the
+     case when the incoming SP is saved at the current SP location.  */
+  int back_chain_saved_p;
+};
 
-  /* Construct the addresses of the spill arrays and the back chain.  */
-  pv_set_to_register (&gpr_spill_addr, S390_SP_REGNUM, 2 * data->gpr_size);
-  pv_set_to_register (&fpr_spill_addr, S390_SP_REGNUM, 16 * data->gpr_size);
-  back_chain_addr = data->gpr[S390_SP_REGNUM - S390_R0_REGNUM];
+/* Return the effective address for an X-style instruction, like:
 
-  /* We have to check for GPR and FPR references using two separate
-     calls to pv_is_array_ref, since the GPR and FPR spill slots are
-     different sizes.  (SPILL is an array, but the thing it tracks
-     isn't really an array.)  */
+        L R1, D2(X2, B2)
 
-  /* Was it a reference to the GPR spill array?  */
-  b = pv_is_array_ref (addr, size, &gpr_spill_addr, 14, data->gpr_size, &i);
-  if (b == pv_definite_yes)
-    {
-      *stack = &data->spill[i];
-      return pv_definite_yes;
-    }
-  if (b == pv_maybe)
-    return pv_maybe;
+   Here, X2 and B2 are registers, and D2 is a signed 20-bit
+   constant; the effective address is the sum of all three.  If either
+   X2 or B2 are zero, then it doesn't contribute to the sum --- this
+   means that r0 can't be used as either X2 or B2.  */
+static pv_t
+s390_addr (struct s390_prologue_data *data,
+          int d2, unsigned int x2, unsigned int b2)
+{
+  pv_t result;
 
-  /* Was it a reference to the FPR spill array?  */
-  b = pv_is_array_ref (addr, size, &fpr_spill_addr, 4, data->fpr_size, &i);
-  if (b == pv_definite_yes)
-    {
-      *stack = &data->spill[14 + i];
-      return pv_definite_yes;
-    }
-  if (b == pv_maybe)
-    return pv_maybe;
-
-  /* Was it a reference to the back chain?
-     This isn't quite right.  We ought to check whether we have
-     actually allocated any new frame at all.  */
-  b = pv_is_array_ref (addr, size, &back_chain_addr, 1, data->gpr_size, &i);
-  if (b == pv_definite_yes)
-    {
-      *stack = &data->back_chain;
-      return pv_definite_yes;
-    }
-  if (b == pv_maybe)
-    return pv_maybe;
+  result = pv_constant (d2);
+  if (x2)
+    result = pv_add (result, data->gpr[x2]);
+  if (b2)
+    result = pv_add (result, data->gpr[b2]);
 
-  /* All the above queries returned definite 'no's.  */
-  return pv_definite_no;
+  return result;
 }
 
-
-/* Do a SIZE-byte store of VALUE to ADDR.  */
+/* Do a SIZE-byte store of VALUE to D2(X2,B2).  */
 static void
-s390_store (struct prologue_value *addr,
-            CORE_ADDR size,
-            struct prologue_value *value,
-           struct s390_prologue_data *data)
+s390_store (struct s390_prologue_data *data,
+           int d2, unsigned int x2, unsigned int b2, CORE_ADDR size,
+           pv_t value)
 {
-  struct prologue_value *stack;
+  pv_t addr = s390_addr (data, d2, x2, b2);
+  pv_t offset;
 
-  /* We can do it if it's definitely a reference to something on the stack.  */
-  if (s390_on_stack (addr, size, data, &stack) == pv_definite_yes)
-    {
-      *stack = *value;
-      return;
-    }
+  /* Check whether we are storing the backchain.  */
+  offset = pv_subtract (data->gpr[S390_SP_REGNUM - S390_R0_REGNUM], addr);
+
+  if (pv_is_constant (offset) && offset.k == 0)
+    if (size == data->gpr_size
+       && pv_is_register_k (value, S390_SP_REGNUM, 0))
+      {
+       data->back_chain_saved_p = 1;
+       return;
+      }
+
+
+  /* Check whether we are storing a register into the stack.  */
+  if (!pv_area_store_would_trash (data->stack, addr))
+    pv_area_store (data->stack, addr, size, value);
 
-  /* Note: If s390_on_stack returns pv_maybe, you might think we should
-     forget our cached values, as any of those might have been hit.
 
-     However, we make the assumption that --since the fields we track
-     are save areas private to compiler, and never directly exposed to 
-     the user-- every access to our data is explicit.  Hence, every 
-     memory access we cannot follow can't hit our data.  */
+  /* Note: If this is some store we cannot identify, you might think we
+     should forget our cached values, as any of those might have been hit.
+
+     However, we make the assumption that the register save areas are only
+     ever stored to once in any given function, and we do recognize these
+     stores.  Thus every store we cannot recognize does not hit our data.  */
 }
 
-/* Do a SIZE-byte load from ADDR into VALUE.  */
-static void
-s390_load (struct prologue_value *addr,
-          CORE_ADDR size,
-          struct prologue_value *value,
-          struct s390_prologue_data *data)
+/* Do a SIZE-byte load from D2(X2,B2).  */
+static pv_t
+s390_load (struct s390_prologue_data *data,
+          int d2, unsigned int x2, unsigned int b2, CORE_ADDR size)
+          
 {
-  struct prologue_value *stack;
+  pv_t addr = s390_addr (data, d2, x2, b2);
+  pv_t offset;
 
   /* If it's a load from an in-line constant pool, then we can
      simulate that, under the assumption that the code isn't
      going to change between the time the processor actually
      executed it creating the current frame, and the time when
      we're analyzing the code to unwind past that frame.  */
-  if (addr->kind == pv_constant)
+  if (pv_is_constant (addr))
     {
       struct section_table *secp;
-      secp = target_section_by_addr (&current_target, addr->k);
+      secp = target_section_by_addr (&current_target, addr.k);
       if (secp != NULL
           && (bfd_get_section_flags (secp->bfd, secp->the_bfd_section)
               & SEC_READONLY))
+        return pv_constant (read_memory_integer (addr.k, size));
+    }
+
+  /* Check whether we are accessing one of our save slots.  */
+  return pv_area_fetch (data->stack, addr, size);
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; we pass
+   this to pv_area_scan.
+
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset in the reg_offset table in
+   PROLOGUE_UNTYPED.  */
+static void
+s390_check_for_saved (void *data_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct s390_prologue_data *data = data_untyped;
+  int i, offset;
+
+  if (!pv_is_register (addr, S390_SP_REGNUM))
+    return;
+
+  offset = 16 * data->gpr_size + 32 - addr.k;
+
+  /* If we are storing the original value of a register, we want to
+     record the CFA offset.  If the same register is stored multiple
+     times, the stack slot with the highest address counts.  */
+  for (i = 0; i < S390_NUM_GPRS; i++)
+    if (size == data->gpr_size
+       && pv_is_register_k (value, S390_R0_REGNUM + i, 0))
+      if (data->gpr_slot[i] == 0
+         || data->gpr_slot[i] > offset)
        {
-          pv_set_to_constant (value, read_memory_integer (addr->k, size));
+         data->gpr_slot[i] = offset;
          return;
        }
-    }
 
-  /* If it's definitely a reference to something on the stack, 
-     we can do that.  */
-  if (s390_on_stack (addr, size, data, &stack) == pv_definite_yes)
-    {
-      *value = *stack;
-      return;
-    }
-
-  /* Otherwise, we don't know the value.  */
-  pv_set_to_unknown (value);
+  for (i = 0; i < S390_NUM_FPRS; i++)
+    if (size == data->fpr_size
+       && pv_is_register_k (value, S390_F0_REGNUM + i, 0))
+      if (data->fpr_slot[i] == 0
+         || data->fpr_slot[i] > offset)
+       {
+         data->fpr_slot[i] = offset;
+         return;
+       }
 }
-            
 
 /* Analyze the prologue of the function starting at START_PC,
    continuing at most until CURRENT_PC.  Initialize DATA to
@@ -1307,6 +857,8 @@ s390_analyze_prologue (struct gdbarch *gdbarch,
   {
     int i;
 
+    data->stack = make_pv_area (S390_SP_REGNUM);
+
     /* For the purpose of prologue tracking, we consider the GPR size to
        be equal to the ABI word size, even if it is actually larger
        (i.e. when running a 32-bit binary under a 64-bit kernel).  */
@@ -1314,15 +866,18 @@ s390_analyze_prologue (struct gdbarch *gdbarch,
     data->fpr_size = 8;
 
     for (i = 0; i < S390_NUM_GPRS; i++)
-      pv_set_to_register (&data->gpr[i], S390_R0_REGNUM + i, 0);
+      data->gpr[i] = pv_register (S390_R0_REGNUM + i, 0);
 
     for (i = 0; i < S390_NUM_FPRS; i++)
-      pv_set_to_register (&data->fpr[i], S390_F0_REGNUM + i, 0);
+      data->fpr[i] = pv_register (S390_F0_REGNUM + i, 0);
 
-    for (i = 0; i < S390_NUM_SPILL_SLOTS; i++)
-      pv_set_to_unknown (&data->spill[i]);
+    for (i = 0; i < S390_NUM_GPRS; i++)
+      data->gpr_slot[i]  = 0;
+
+    for (i = 0; i < S390_NUM_FPRS; i++)
+      data->fpr_slot[i]  = 0;
 
-    pv_set_to_unknown (&data->back_chain);
+    data->back_chain_saved_p = 0;
   }
 
   /* Start interpreting instructions, until we hit the frame's
@@ -1332,13 +887,19 @@ s390_analyze_prologue (struct gdbarch *gdbarch,
       bfd_byte insn[S390_MAX_INSTR_SIZE];
       int insn_len = s390_readinstruction (insn, pc);
 
+      bfd_byte dummy[S390_MAX_INSTR_SIZE] = { 0 };
+      bfd_byte *insn32 = word_size == 4 ? insn : dummy;
+      bfd_byte *insn64 = word_size == 8 ? insn : dummy;
+
       /* Fields for various kinds of instructions.  */
       unsigned int b2, r1, r2, x2, r3;
       int i2, d2;
 
-      /* The values of SP, FP, and back chain before this instruction,
+      /* The values of SP and FP before this instruction,
          for detecting instructions that change them.  */
-      struct prologue_value pre_insn_sp, pre_insn_fp, pre_insn_back_chain;
+      pv_t pre_insn_sp, pre_insn_fp;
+      /* Likewise for the flag whether the back chain was saved.  */
+      int pre_insn_back_chain_saved_p;
 
       /* If we got an error trying to read the instruction, report it.  */
       if (insn_len < 0)
@@ -1351,288 +912,128 @@ s390_analyze_prologue (struct gdbarch *gdbarch,
 
       pre_insn_sp = data->gpr[S390_SP_REGNUM - S390_R0_REGNUM];
       pre_insn_fp = data->gpr[S390_FRAME_REGNUM - S390_R0_REGNUM];
-      pre_insn_back_chain = data->back_chain;
-
-      /* LHI r1, i2 --- load halfword immediate */
-      if (word_size == 4
-         && is_ri (insn, op1_lhi, op2_lhi, &r1, &i2))
-        pv_set_to_constant (&data->gpr[r1], i2);
-
-      /* LGHI r1, i2 --- load halfword immediate (64-bit version) */
-      else if (word_size == 8
-              && is_ri (insn, op1_lghi, op2_lghi, &r1, &i2))
-        pv_set_to_constant (&data->gpr[r1], i2);
-
-      /* LR r1, r2 --- load from register */
-      else if (word_size == 4
-              && is_rr (insn, op_lr, &r1, &r2))
-        data->gpr[r1] = data->gpr[r2];
-
-      /* LGR r1, r2 --- load from register (64-bit version) */
-      else if (word_size == 8
-               && is_rre (insn, op_lgr, &r1, &r2))
-        data->gpr[r1] = data->gpr[r2];
-
-      /* L r1, d2(x2, b2) --- load */
-      else if (word_size == 4
-              && is_rx (insn, op_l, &r1, &d2, &x2, &b2))
-        {
-          struct prologue_value addr;
-
-          compute_x_addr (&addr, data->gpr, d2, x2, b2);
-         s390_load (&addr, 4, &data->gpr[r1], data);
-        }
-
-      /* LY r1, d2(x2, b2) --- load (long-displacement version) */
-      else if (word_size == 4
-              && is_rxy (insn, op1_ly, op2_ly, &r1, &d2, &x2, &b2))
-        {
-          struct prologue_value addr;
-
-          compute_x_addr (&addr, data->gpr, d2, x2, b2);
-         s390_load (&addr, 4, &data->gpr[r1], data);
-        }
-
-      /* LG r1, d2(x2, b2) --- load (64-bit version) */
-      else if (word_size == 8
-              && is_rxy (insn, op1_lg, op2_lg, &r1, &d2, &x2, &b2))
-        {
-          struct prologue_value addr;
-
-          compute_x_addr (&addr, data->gpr, d2, x2, b2);
-         s390_load (&addr, 8, &data->gpr[r1], data);
-        }
-
-      /* ST r1, d2(x2, b2) --- store */
-      else if (word_size == 4
-              && is_rx (insn, op_st, &r1, &d2, &x2, &b2))
-        {
-          struct prologue_value addr;
-
-          compute_x_addr (&addr, data->gpr, d2, x2, b2);
-         s390_store (&addr, 4, &data->gpr[r1], data);
-        }
-
-      /* STY r1, d2(x2, b2) --- store (long-displacement version) */
-      else if (word_size == 4
-              && is_rxy (insn, op1_sty, op2_sty, &r1, &d2, &x2, &b2))
-        {
-          struct prologue_value addr;
-
-          compute_x_addr (&addr, data->gpr, d2, x2, b2);
-         s390_store (&addr, 4, &data->gpr[r1], data);
-        }
-
-      /* STG r1, d2(x2, b2) --- store (64-bit version) */
-      else if (word_size == 8
-              && is_rxy (insn, op1_stg, op2_stg, &r1, &d2, &x2, &b2))
-        {
-          struct prologue_value addr;
-
-          compute_x_addr (&addr, data->gpr, d2, x2, b2);
-         s390_store (&addr, 8, &data->gpr[r1], data);
-        }
-
-      /* STD r1, d2(x2,b2) --- store floating-point register  */
+      pre_insn_back_chain_saved_p = data->back_chain_saved_p;
+
+
+      /* LHI r1, i2 --- load halfword immediate.  */
+      /* LGHI r1, i2 --- load halfword immediate (64-bit version).  */
+      /* LGFI r1, i2 --- load fullword immediate.  */
+      if (is_ri (insn32, op1_lhi, op2_lhi, &r1, &i2)
+          || is_ri (insn64, op1_lghi, op2_lghi, &r1, &i2)
+          || is_ril (insn, op1_lgfi, op2_lgfi, &r1, &i2))
+       data->gpr[r1] = pv_constant (i2);
+
+      /* LR r1, r2 --- load from register.  */
+      /* LGR r1, r2 --- load from register (64-bit version).  */
+      else if (is_rr (insn32, op_lr, &r1, &r2)
+              || is_rre (insn64, op_lgr, &r1, &r2))
+       data->gpr[r1] = data->gpr[r2];
+
+      /* L r1, d2(x2, b2) --- load.  */
+      /* LY r1, d2(x2, b2) --- load (long-displacement version).  */
+      /* LG r1, d2(x2, b2) --- load (64-bit version).  */
+      else if (is_rx (insn32, op_l, &r1, &d2, &x2, &b2)
+              || is_rxy (insn32, op1_ly, op2_ly, &r1, &d2, &x2, &b2)
+              || is_rxy (insn64, op1_lg, op2_lg, &r1, &d2, &x2, &b2))
+       data->gpr[r1] = s390_load (data, d2, x2, b2, data->gpr_size);
+
+      /* ST r1, d2(x2, b2) --- store.  */
+      /* STY r1, d2(x2, b2) --- store (long-displacement version).  */
+      /* STG r1, d2(x2, b2) --- store (64-bit version).  */
+      else if (is_rx (insn32, op_st, &r1, &d2, &x2, &b2)
+              || is_rxy (insn32, op1_sty, op2_sty, &r1, &d2, &x2, &b2)
+              || is_rxy (insn64, op1_stg, op2_stg, &r1, &d2, &x2, &b2))
+       s390_store (data, d2, x2, b2, data->gpr_size, data->gpr[r1]);
+
+      /* STD r1, d2(x2,b2) --- store floating-point register.  */
       else if (is_rx (insn, op_std, &r1, &d2, &x2, &b2))
+       s390_store (data, d2, x2, b2, data->fpr_size, data->fpr[r1]);
+
+      /* STM r1, r3, d2(b2) --- store multiple.  */
+      /* STMY r1, r3, d2(b2) --- store multiple (long-displacement version).  */
+      /* STMG r1, r3, d2(b2) --- store multiple (64-bit version).  */
+      else if (is_rs (insn32, op_stm, &r1, &r3, &d2, &b2)
+              || is_rsy (insn32, op1_stmy, op2_stmy, &r1, &r3, &d2, &b2)
+              || is_rsy (insn64, op1_stmg, op2_stmg, &r1, &r3, &d2, &b2))
         {
-          struct prologue_value addr;
-
-          compute_x_addr (&addr, data->gpr, d2, x2, b2);
-          s390_store (&addr, 8, &data->fpr[r1], data);
-        }
-
-      /* STM r1, r3, d2(b2) --- store multiple */
-      else if (word_size == 4
-              && is_rs (insn, op_stm, &r1, &r3, &d2, &b2))
-        {
-          int regnum;
-          int offset;
-          struct prologue_value addr;
-
-          for (regnum = r1, offset = 0;
-               regnum <= r3;
-               regnum++, offset += 4)
-            {
-              compute_x_addr (&addr, data->gpr, d2 + offset, 0, b2);
-              s390_store (&addr, 4, &data->gpr[regnum], data);
-            }
-        }
-
-      /* STMY r1, r3, d2(b2) --- store multiple (long-displacement version) */
-      else if (word_size == 4
-              && is_rsy (insn, op1_stmy, op2_stmy, &r1, &r3, &d2, &b2))
-        {
-          int regnum;
-          int offset;
-          struct prologue_value addr;
-
-          for (regnum = r1, offset = 0;
-               regnum <= r3;
-               regnum++, offset += 4)
-            {
-              compute_x_addr (&addr, data->gpr, d2 + offset, 0, b2);
-              s390_store (&addr, 4, &data->gpr[regnum], data);
-            }
+          for (; r1 <= r3; r1++, d2 += data->gpr_size)
+           s390_store (data, d2, 0, b2, data->gpr_size, data->gpr[r1]);
         }
 
-      /* STMG r1, r3, d2(b2) --- store multiple (64-bit version) */
-      else if (word_size == 8
-              && is_rsy (insn, op1_stmg, op2_stmg, &r1, &r3, &d2, &b2))
-        {
-          int regnum;
-          int offset;
-          struct prologue_value addr;
-
-          for (regnum = r1, offset = 0;
-               regnum <= r3;
-               regnum++, offset += 8)
-            {
-              compute_x_addr (&addr, data->gpr, d2 + offset, 0, b2);
-              s390_store (&addr, 8, &data->gpr[regnum], data);
-            }
-        }
-
-      /* AHI r1, i2 --- add halfword immediate */
-      else if (word_size == 4
-              && is_ri (insn, op1_ahi, op2_ahi, &r1, &i2))
-        pv_add_constant (&data->gpr[r1], i2);
-
-      /* AGHI r1, i2 --- add halfword immediate (64-bit version) */
-      else if (word_size == 8
-               && is_ri (insn, op1_aghi, op2_aghi, &r1, &i2))
-        pv_add_constant (&data->gpr[r1], i2);
-
-      /* AR r1, r2 -- add register */
-      else if (word_size == 4
-              && is_rr (insn, op_ar, &r1, &r2))
-        pv_add (&data->gpr[r1], &data->gpr[r1], &data->gpr[r2]);
-
-      /* AGR r1, r2 -- add register (64-bit version) */
-      else if (word_size == 8
-              && is_rre (insn, op_agr, &r1, &r2))
-        pv_add (&data->gpr[r1], &data->gpr[r1], &data->gpr[r2]);
-
-      /* A r1, d2(x2, b2) -- add */
-      else if (word_size == 4
-              && is_rx (insn, op_a, &r1, &d2, &x2, &b2))
-       {
-          struct prologue_value addr;
-          struct prologue_value value;
-
-          compute_x_addr (&addr, data->gpr, d2, x2, b2);
-         s390_load (&addr, 4, &value, data);
-       
-         pv_add (&data->gpr[r1], &data->gpr[r1], &value);
-       }
-
-      /* AY r1, d2(x2, b2) -- add (long-displacement version) */
-      else if (word_size == 4
-              && is_rxy (insn, op1_ay, op2_ay, &r1, &d2, &x2, &b2))
-       {
-          struct prologue_value addr;
-          struct prologue_value value;
-
-          compute_x_addr (&addr, data->gpr, d2, x2, b2);
-         s390_load (&addr, 4, &value, data);
-       
-         pv_add (&data->gpr[r1], &data->gpr[r1], &value);
-       }
-
-      /* AG r1, d2(x2, b2) -- add (64-bit version) */
-      else if (word_size == 8
-              && is_rxy (insn, op1_ag, op2_ag, &r1, &d2, &x2, &b2))
-       {
-          struct prologue_value addr;
-          struct prologue_value value;
-
-          compute_x_addr (&addr, data->gpr, d2, x2, b2);
-         s390_load (&addr, 8, &value, data);
-       
-         pv_add (&data->gpr[r1], &data->gpr[r1], &value);
-       }
-
-      /* SR r1, r2 -- subtract register */
-      else if (word_size == 4
-              && is_rr (insn, op_sr, &r1, &r2))
-        pv_subtract (&data->gpr[r1], &data->gpr[r1], &data->gpr[r2]);
-
-      /* SGR r1, r2 -- subtract register (64-bit version) */
-      else if (word_size == 8
-              && is_rre (insn, op_sgr, &r1, &r2))
-        pv_subtract (&data->gpr[r1], &data->gpr[r1], &data->gpr[r2]);
-
-      /* S r1, d2(x2, b2) -- subtract */
-      else if (word_size == 4
-              && is_rx (insn, op_s, &r1, &d2, &x2, &b2))
-       {
-          struct prologue_value addr;
-          struct prologue_value value;
-
-          compute_x_addr (&addr, data->gpr, d2, x2, b2);
-         s390_load (&addr, 4, &value, data);
-       
-         pv_subtract (&data->gpr[r1], &data->gpr[r1], &value);
-       }
-
-      /* SY r1, d2(x2, b2) -- subtract (long-displacement version) */
-      else if (word_size == 4
-              && is_rxy (insn, op1_sy, op2_sy, &r1, &d2, &x2, &b2))
-       {
-          struct prologue_value addr;
-          struct prologue_value value;
-
-          compute_x_addr (&addr, data->gpr, d2, x2, b2);
-         s390_load (&addr, 4, &value, data);
-       
-         pv_subtract (&data->gpr[r1], &data->gpr[r1], &value);
-       }
-
-      /* SG r1, d2(x2, b2) -- subtract (64-bit version) */
-      else if (word_size == 8
-              && is_rxy (insn, op1_sg, op2_sg, &r1, &d2, &x2, &b2))
-       {
-          struct prologue_value addr;
-          struct prologue_value value;
-
-          compute_x_addr (&addr, data->gpr, d2, x2, b2);
-         s390_load (&addr, 8, &value, data);
-       
-         pv_subtract (&data->gpr[r1], &data->gpr[r1], &value);
-       }
-
-      /* NR r1, r2 --- logical and */
-      else if (word_size == 4
-              && is_rr (insn, op_nr, &r1, &r2))
-        pv_logical_and (&data->gpr[r1], &data->gpr[r1], &data->gpr[r2]);
-
-      /* NGR r1, r2 >--- logical and (64-bit version) */
-      else if (word_size == 8
-               && is_rre (insn, op_ngr, &r1, &r2))
-        pv_logical_and (&data->gpr[r1], &data->gpr[r1], &data->gpr[r2]);
-
-      /* LA r1, d2(x2, b2) --- load address */
-      else if (is_rx (insn, op_la, &r1, &d2, &x2, &b2))
-        compute_x_addr (&data->gpr[r1], data->gpr, d2, x2, b2);
-
-      /* LAY r1, d2(x2, b2) --- load address (long-displacement version) */
-      else if (is_rxy (insn, op1_lay, op2_lay, &r1, &d2, &x2, &b2))
-        compute_x_addr (&data->gpr[r1], data->gpr, d2, x2, b2);
-
-      /* LARL r1, i2 --- load address relative long */
+      /* AHI r1, i2 --- add halfword immediate.  */
+      /* AGHI r1, i2 --- add halfword immediate (64-bit version).  */
+      /* AFI r1, i2 --- add fullword immediate.  */
+      /* AGFI r1, i2 --- add fullword immediate (64-bit version).  */
+      else if (is_ri (insn32, op1_ahi, op2_ahi, &r1, &i2)
+              || is_ri (insn64, op1_aghi, op2_aghi, &r1, &i2)
+              || is_ril (insn32, op1_afi, op2_afi, &r1, &i2)
+              || is_ril (insn64, op1_agfi, op2_agfi, &r1, &i2))
+       data->gpr[r1] = pv_add_constant (data->gpr[r1], i2);
+
+      /* ALFI r1, i2 --- add logical immediate.  */
+      /* ALGFI r1, i2 --- add logical immediate (64-bit version).  */
+      else if (is_ril (insn32, op1_alfi, op2_alfi, &r1, &i2)
+              || is_ril (insn64, op1_algfi, op2_algfi, &r1, &i2))
+       data->gpr[r1] = pv_add_constant (data->gpr[r1],
+                                        (CORE_ADDR)i2 & 0xffffffff);
+
+      /* AR r1, r2 -- add register.  */
+      /* AGR r1, r2 -- add register (64-bit version).  */
+      else if (is_rr (insn32, op_ar, &r1, &r2)
+              || is_rre (insn64, op_agr, &r1, &r2))
+       data->gpr[r1] = pv_add (data->gpr[r1], data->gpr[r2]);
+
+      /* A r1, d2(x2, b2) -- add.  */
+      /* AY r1, d2(x2, b2) -- add (long-displacement version).  */
+      /* AG r1, d2(x2, b2) -- add (64-bit version).  */
+      else if (is_rx (insn32, op_a, &r1, &d2, &x2, &b2)
+              || is_rxy (insn32, op1_ay, op2_ay, &r1, &d2, &x2, &b2)
+              || is_rxy (insn64, op1_ag, op2_ag, &r1, &d2, &x2, &b2))
+       data->gpr[r1] = pv_add (data->gpr[r1],
+                               s390_load (data, d2, x2, b2, data->gpr_size));
+
+      /* SLFI r1, i2 --- subtract logical immediate.  */
+      /* SLGFI r1, i2 --- subtract logical immediate (64-bit version).  */
+      else if (is_ril (insn32, op1_slfi, op2_slfi, &r1, &i2)
+              || is_ril (insn64, op1_slgfi, op2_slgfi, &r1, &i2))
+       data->gpr[r1] = pv_add_constant (data->gpr[r1],
+                                        -((CORE_ADDR)i2 & 0xffffffff));
+
+      /* SR r1, r2 -- subtract register.  */
+      /* SGR r1, r2 -- subtract register (64-bit version).  */
+      else if (is_rr (insn32, op_sr, &r1, &r2)
+              || is_rre (insn64, op_sgr, &r1, &r2))
+       data->gpr[r1] = pv_subtract (data->gpr[r1], data->gpr[r2]);
+
+      /* S r1, d2(x2, b2) -- subtract.  */
+      /* SY r1, d2(x2, b2) -- subtract (long-displacement version).  */
+      /* SG r1, d2(x2, b2) -- subtract (64-bit version).  */
+      else if (is_rx (insn32, op_s, &r1, &d2, &x2, &b2)
+              || is_rxy (insn32, op1_sy, op2_sy, &r1, &d2, &x2, &b2)
+              || is_rxy (insn64, op1_sg, op2_sg, &r1, &d2, &x2, &b2))
+       data->gpr[r1] = pv_subtract (data->gpr[r1],
+                               s390_load (data, d2, x2, b2, data->gpr_size));
+
+      /* LA r1, d2(x2, b2) --- load address.  */
+      /* LAY r1, d2(x2, b2) --- load address (long-displacement version).  */
+      else if (is_rx (insn, op_la, &r1, &d2, &x2, &b2)
+               || is_rxy (insn, op1_lay, op2_lay, &r1, &d2, &x2, &b2))
+       data->gpr[r1] = s390_addr (data, d2, x2, b2);
+
+      /* LARL r1, i2 --- load address relative long.  */
       else if (is_ril (insn, op1_larl, op2_larl, &r1, &i2))
-        pv_set_to_constant (&data->gpr[r1], pc + i2 * 2);
+       data->gpr[r1] = pv_constant (pc + i2 * 2);
 
-      /* BASR r1, 0 --- branch and save
+      /* BASR r1, 0 --- branch and save.
          Since r2 is zero, this saves the PC in r1, but doesn't branch.  */
       else if (is_rr (insn, op_basr, &r1, &r2)
                && r2 == 0)
-        pv_set_to_constant (&data->gpr[r1], next_pc);
+       data->gpr[r1] = pv_constant (next_pc);
 
-      /* BRAS r1, i2 --- branch relative and save */
+      /* BRAS r1, i2 --- branch relative and save */
       else if (is_ri (insn, op1_bras, op2_bras, &r1, &i2))
         {
-          pv_set_to_constant (&data->gpr[r1], next_pc);
+          data->gpr[r1] = pv_constant (next_pc);
           next_pc = pc + i2 * 2;
 
           /* We'd better not interpret any backward branches.  We'll
@@ -1666,18 +1067,26 @@ s390_analyze_prologue (struct gdbarch *gdbarch,
          restore instructions.  (The back chain is never restored,
          just popped.)  */
       {
-        struct prologue_value *sp = &data->gpr[S390_SP_REGNUM - S390_R0_REGNUM];
-        struct prologue_value *fp = &data->gpr[S390_FRAME_REGNUM - S390_R0_REGNUM];
+        pv_t sp = data->gpr[S390_SP_REGNUM - S390_R0_REGNUM];
+        pv_t fp = data->gpr[S390_FRAME_REGNUM - S390_R0_REGNUM];
         
-        if ((! pv_is_identical (&pre_insn_sp, sp)
-             && ! pv_is_register (sp, S390_SP_REGNUM, 0))
-            || (! pv_is_identical (&pre_insn_fp, fp)
-                && ! pv_is_register (fp, S390_FRAME_REGNUM, 0))
-            || ! pv_is_identical (&pre_insn_back_chain, &data->back_chain))
+        if ((! pv_is_identical (pre_insn_sp, sp)
+             && ! pv_is_register_k (sp, S390_SP_REGNUM, 0)
+            && sp.kind != pvk_unknown)
+            || (! pv_is_identical (pre_insn_fp, fp)
+                && ! pv_is_register_k (fp, S390_FRAME_REGNUM, 0)
+               && fp.kind != pvk_unknown)
+            || pre_insn_back_chain_saved_p != data->back_chain_saved_p)
           result = next_pc;
       }
     }
 
+  /* Record where all the registers were saved.  */
+  pv_area_scan (data->stack, s390_check_for_saved, data);
+
+  free_pv_area (data->stack);
+  data->stack = NULL;
+
   return result;
 }
 
@@ -1760,12 +1169,13 @@ s390_prologue_frame_unwind_cache (struct frame_info *next_frame,
                                  struct s390_unwind_cache *info)
 {
   struct gdbarch *gdbarch = get_frame_arch (next_frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   int word_size = gdbarch_ptr_bit (gdbarch) / 8;
   struct s390_prologue_data data;
-  struct prologue_value *fp = &data.gpr[S390_FRAME_REGNUM - S390_R0_REGNUM];
-  struct prologue_value *sp = &data.gpr[S390_SP_REGNUM - S390_R0_REGNUM];
-  int slot_num;
-  CORE_ADDR slot_addr;
+  pv_t *fp = &data.gpr[S390_FRAME_REGNUM - S390_R0_REGNUM];
+  pv_t *sp = &data.gpr[S390_SP_REGNUM - S390_R0_REGNUM];
+  int i;
+  CORE_ADDR cfa;
   CORE_ADDR func;
   CORE_ADDR result;
   ULONGEST reg;
@@ -1777,7 +1187,7 @@ s390_prologue_frame_unwind_cache (struct frame_info *next_frame,
      bother searching for it -- with modern compilers this would be mostly
      pointless anyway.  Trust that we'll either have valid DWARF-2 CFI data
      or else a valid backchain ...  */
-  func = frame_func_unwind (next_frame);
+  func = frame_func_unwind (next_frame, NORMAL_FRAME);
   if (!func)
     return 0;
 
@@ -1790,7 +1200,7 @@ s390_prologue_frame_unwind_cache (struct frame_info *next_frame,
   /* If this was successful, we should have found the instruction that
      sets the stack pointer register to the previous value of the stack 
      pointer minus the frame size.  */
-  if (sp->kind != pv_register || sp->reg != S390_SP_REGNUM)
+  if (!pv_is_register (*sp, S390_SP_REGNUM))
     return 0;
 
   /* A frame size of zero at this point can mean either a real 
@@ -1802,10 +1212,10 @@ s390_prologue_frame_unwind_cache (struct frame_info *next_frame,
       /* If the next frame is a NORMAL_FRAME, this frame *cannot* have frame 
         size zero.  This is only possible if the next frame is a sentinel 
         frame, a dummy frame, or a signal trampoline frame.  */
-      if (get_frame_type (next_frame) == NORMAL_FRAME
-         /* For some reason, sentinel frames are NORMAL_FRAMEs
-            -- but they have negative frame level.  */
-         && frame_relative_level (next_frame) >= 0)
+      /* FIXME: cagney/2004-05-01: This sanity check shouldn't be
+        needed, instead the code should simpliy rely on its
+        analysis.  */
+      if (get_frame_type (next_frame) == NORMAL_FRAME)
        return 0;
 
       /* If we really have a frameless function, %r14 must be valid
@@ -1822,11 +1232,10 @@ s390_prologue_frame_unwind_cache (struct frame_info *next_frame,
             Recognize this case by looking ahead a bit ...  */
 
          struct s390_prologue_data data2;
-         struct prologue_value *sp = &data2.gpr[S390_SP_REGNUM - S390_R0_REGNUM];
+         pv_t *sp = &data2.gpr[S390_SP_REGNUM - S390_R0_REGNUM];
 
          if (!(s390_analyze_prologue (gdbarch, func, (CORE_ADDR)-1, &data2)
-               && sp->kind == pv_register
-               && sp->reg == S390_SP_REGNUM
+               && pv_is_register (*sp, S390_SP_REGNUM)
                && sp->k != 0))
            return 0;
        }
@@ -1840,7 +1249,7 @@ s390_prologue_frame_unwind_cache (struct frame_info *next_frame,
      as the stack pointer, we're probably using it.  If it holds
      some other value -- even a constant offset -- it is most
      likely used as temp register.  */
-  if (pv_is_identical (sp, fp))
+  if (pv_is_identical (*sp, *fp))
     frame_pointer = S390_FRAME_REGNUM;
   else
     frame_pointer = S390_SP_REGNUM;
@@ -1849,9 +1258,9 @@ s390_prologue_frame_unwind_cache (struct frame_info *next_frame,
      treat it as frameless if we're currently within the function epilog 
      code at a point where the frame pointer has already been restored.  
      This can only happen in an innermost frame.  */
-  if (size > 0
-      && (get_frame_type (next_frame) != NORMAL_FRAME
-         || frame_relative_level (next_frame) < 0))
+  /* FIXME: cagney/2004-05-01: This sanity check shouldn't be needed,
+     instead the code should simpliy rely on its analysis.  */
+  if (size > 0 && get_frame_type (next_frame) != NORMAL_FRAME)
     {
       /* See the comment in s390_in_function_epilogue_p on why this is
         not completely reliable ...  */
@@ -1868,33 +1277,31 @@ s390_prologue_frame_unwind_cache (struct frame_info *next_frame,
      add back the frame size to arrive that the previous frame's 
      stack pointer value.  */
   prev_sp = frame_unwind_register_unsigned (next_frame, frame_pointer) + size;
+  cfa = prev_sp + 16*word_size + 32;
 
-  /* Scan the spill array; if a spill slot says it holds the
-     original value of some register, then record that slot's
-     address as the place that register was saved.  */
+  /* Record the addresses of all register spill slots the prologue parser
+     has recognized.  Consider only registers defined as call-saved by the
+     ABI; for call-clobbered registers the parser may have recognized
+     spurious stores.  */
 
-  /* Slots for %r2 .. %r15.  */
-  for (slot_num = 0, slot_addr = prev_sp + 2 * data.gpr_size;
-       slot_num < 14;
-       slot_num++, slot_addr += data.gpr_size)
-    {
-      struct prologue_value *slot = &data.spill[slot_num];
+  for (i = 6; i <= 15; i++)
+    if (data.gpr_slot[i] != 0)
+      info->saved_regs[S390_R0_REGNUM + i].addr = cfa - data.gpr_slot[i];
 
-      if (slot->kind == pv_register
-          && slot->k == 0)
-        info->saved_regs[slot->reg].addr = slot_addr;
-    }
-
-  /* Slots for %f0 .. %f6.  */
-  for (slot_num = 14, slot_addr = prev_sp + 16 * data.gpr_size;
-       slot_num < S390_NUM_SPILL_SLOTS;
-       slot_num++, slot_addr += data.fpr_size)
+  switch (tdep->abi)
     {
-      struct prologue_value *slot = &data.spill[slot_num];
+    case ABI_LINUX_S390:
+      if (data.fpr_slot[4] != 0)
+        info->saved_regs[S390_F4_REGNUM].addr = cfa - data.fpr_slot[4];
+      if (data.fpr_slot[6] != 0)
+        info->saved_regs[S390_F6_REGNUM].addr = cfa - data.fpr_slot[6];
+      break;
 
-      if (slot->kind == pv_register
-          && slot->k == 0)
-        info->saved_regs[slot->reg].addr = slot_addr;
+    case ABI_LINUX_ZSERIES:
+      for (i = 8; i <= 15; i++)
+       if (data.fpr_slot[i] != 0)
+         info->saved_regs[S390_F0_REGNUM + i].addr = cfa - data.fpr_slot[i];
+      break;
     }
 
   /* Function return will set PC to %r14.  */
@@ -2015,12 +1422,12 @@ s390_frame_prev_register (struct frame_info *next_frame,
                          void **this_prologue_cache,
                          int regnum, int *optimizedp,
                          enum lval_type *lvalp, CORE_ADDR *addrp,
-                         int *realnump, void *bufferp)
+                         int *realnump, gdb_byte *bufferp)
 {
   struct s390_unwind_cache *info
     = s390_frame_unwind_cache (next_frame, this_prologue_cache);
-  trad_frame_prev_register (next_frame, info->saved_regs, regnum,
-                            optimizedp, lvalp, addrp, realnump, bufferp);
+  trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
+                               optimizedp, lvalp, addrp, realnump, bufferp);
 }
 
 static const struct frame_unwind s390_frame_unwind = {
@@ -2036,27 +1443,29 @@ s390_frame_sniffer (struct frame_info *next_frame)
 }
 
 
-/* PLT stub stack frames.  */
-
-struct s390_pltstub_unwind_cache {
+/* Code stubs and their stack frames.  For things like PLTs and NULL
+   function calls (where there is no true frame and the return address
+   is in the RETADDR register).  */
 
+struct s390_stub_unwind_cache
+{
   CORE_ADDR frame_base;
   struct trad_frame_saved_reg *saved_regs;
 };
 
-static struct s390_pltstub_unwind_cache *
-s390_pltstub_frame_unwind_cache (struct frame_info *next_frame,
-                                void **this_prologue_cache)
+static struct s390_stub_unwind_cache *
+s390_stub_frame_unwind_cache (struct frame_info *next_frame,
+                             void **this_prologue_cache)
 {
   struct gdbarch *gdbarch = get_frame_arch (next_frame);
   int word_size = gdbarch_ptr_bit (gdbarch) / 8;
-  struct s390_pltstub_unwind_cache *info;
+  struct s390_stub_unwind_cache *info;
   ULONGEST reg;
 
   if (*this_prologue_cache)
     return *this_prologue_cache;
 
-  info = FRAME_OBSTACK_ZALLOC (struct s390_pltstub_unwind_cache);
+  info = FRAME_OBSTACK_ZALLOC (struct s390_stub_unwind_cache);
   *this_prologue_cache = info;
   info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
 
@@ -2071,41 +1480,48 @@ s390_pltstub_frame_unwind_cache (struct frame_info *next_frame,
 }
 
 static void
-s390_pltstub_frame_this_id (struct frame_info *next_frame,
-                           void **this_prologue_cache,
-                           struct frame_id *this_id)
+s390_stub_frame_this_id (struct frame_info *next_frame,
+                        void **this_prologue_cache,
+                        struct frame_id *this_id)
 {
-  struct s390_pltstub_unwind_cache *info
-    = s390_pltstub_frame_unwind_cache (next_frame, this_prologue_cache);
+  struct s390_stub_unwind_cache *info
+    = s390_stub_frame_unwind_cache (next_frame, this_prologue_cache);
   *this_id = frame_id_build (info->frame_base, frame_pc_unwind (next_frame));
 }
 
 static void
-s390_pltstub_frame_prev_register (struct frame_info *next_frame,
-                                 void **this_prologue_cache,
-                                 int regnum, int *optimizedp,
-                                 enum lval_type *lvalp, CORE_ADDR *addrp,
-                                 int *realnump, void *bufferp)
+s390_stub_frame_prev_register (struct frame_info *next_frame,
+                              void **this_prologue_cache,
+                              int regnum, int *optimizedp,
+                              enum lval_type *lvalp, CORE_ADDR *addrp,
+                              int *realnump, gdb_byte *bufferp)
 {
-  struct s390_pltstub_unwind_cache *info
-    = s390_pltstub_frame_unwind_cache (next_frame, this_prologue_cache);
-  trad_frame_prev_register (next_frame, info->saved_regs, regnum,
-                            optimizedp, lvalp, addrp, realnump, bufferp);
+  struct s390_stub_unwind_cache *info
+    = s390_stub_frame_unwind_cache (next_frame, this_prologue_cache);
+  trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
+                               optimizedp, lvalp, addrp, realnump, bufferp);
 }
 
-static const struct frame_unwind s390_pltstub_frame_unwind = {
+static const struct frame_unwind s390_stub_frame_unwind = {
   NORMAL_FRAME,
-  s390_pltstub_frame_this_id,
-  s390_pltstub_frame_prev_register
+  s390_stub_frame_this_id,
+  s390_stub_frame_prev_register
 };
 
 static const struct frame_unwind *
-s390_pltstub_frame_sniffer (struct frame_info *next_frame)
-{
-  if (!in_plt_section (frame_pc_unwind (next_frame), NULL))
-    return NULL;
-
-  return &s390_pltstub_frame_unwind;
+s390_stub_frame_sniffer (struct frame_info *next_frame)
+{
+  CORE_ADDR addr_in_block;
+  bfd_byte insn[S390_MAX_INSTR_SIZE];
+
+  /* If the current PC points to non-readable memory, we assume we
+     have trapped due to an invalid function pointer call.  We handle
+     the non-existing current function like a PLT stub.  */
+  addr_in_block = frame_unwind_address_in_block (next_frame, NORMAL_FRAME);
+  if (in_plt_section (addr_in_block, NULL)
+      || s390_readinstruction (insn, frame_pc_unwind (next_frame)) < 0)
+    return &s390_stub_frame_unwind;
+  return NULL;
 }
 
 
@@ -2144,7 +1560,7 @@ s390_sigtramp_frame_unwind_cache (struct frame_info *next_frame,
        ucontext (contains sigregs at offset 5 words)  */
   if (next_ra == next_cfa)
     {
-      sigreg_ptr = next_cfa + 8 + 128 + 5*word_size;
+      sigreg_ptr = next_cfa + 8 + 128 + align_up (5*word_size, 8);
     }
 
   /* Old-style RT frame and all non-RT frames:
@@ -2222,12 +1638,12 @@ s390_sigtramp_frame_prev_register (struct frame_info *next_frame,
                                   void **this_prologue_cache,
                                   int regnum, int *optimizedp,
                                   enum lval_type *lvalp, CORE_ADDR *addrp,
-                                  int *realnump, void *bufferp)
+                                  int *realnump, gdb_byte *bufferp)
 {
   struct s390_sigtramp_unwind_cache *info
     = s390_sigtramp_frame_unwind_cache (next_frame, this_prologue_cache);
-  trad_frame_prev_register (next_frame, info->saved_regs, regnum,
-                            optimizedp, lvalp, addrp, realnump, bufferp);
+  trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
+                               optimizedp, lvalp, addrp, realnump, bufferp);
 }
 
 static const struct frame_unwind s390_sigtramp_frame_unwind = {
@@ -2298,6 +1714,54 @@ s390_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
 }
 
 
+/* DWARF-2 frame support.  */
+
+static void
+s390_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+                            struct dwarf2_frame_state_reg *reg,
+                           struct frame_info *next_frame)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  switch (tdep->abi)
+    {
+    case ABI_LINUX_S390:
+      /* Call-saved registers.  */
+      if ((regnum >= S390_R6_REGNUM && regnum <= S390_R15_REGNUM)
+         || regnum == S390_F4_REGNUM
+         || regnum == S390_F6_REGNUM)
+       reg->how = DWARF2_FRAME_REG_SAME_VALUE;
+
+      /* Call-clobbered registers.  */
+      else if ((regnum >= S390_R0_REGNUM && regnum <= S390_R5_REGNUM)
+              || (regnum >= S390_F0_REGNUM && regnum <= S390_F15_REGNUM
+                  && regnum != S390_F4_REGNUM && regnum != S390_F6_REGNUM))
+       reg->how = DWARF2_FRAME_REG_UNDEFINED;
+
+      /* The return address column.  */
+      else if (regnum == S390_PC_REGNUM)
+       reg->how = DWARF2_FRAME_REG_RA;
+      break;
+
+    case ABI_LINUX_ZSERIES:
+      /* Call-saved registers.  */
+      if ((regnum >= S390_R6_REGNUM && regnum <= S390_R15_REGNUM)
+         || (regnum >= S390_F8_REGNUM && regnum <= S390_F15_REGNUM))
+       reg->how = DWARF2_FRAME_REG_SAME_VALUE;
+
+      /* Call-clobbered registers.  */
+      else if ((regnum >= S390_R0_REGNUM && regnum <= S390_R5_REGNUM)
+              || (regnum >= S390_F0_REGNUM && regnum <= S390_F7_REGNUM))
+       reg->how = DWARF2_FRAME_REG_UNDEFINED;
+
+      /* The return address column.  */
+      else if (regnum == S390_PC_REGNUM)
+       reg->how = DWARF2_FRAME_REG_RA;
+      break;
+    }
+}
+
+
 /* Dummy function calls.  */
 
 /* Return non-zero if TYPE is an integer-like type, zero otherwise.
@@ -2444,16 +1908,16 @@ s390_function_arg_integer (struct type *type)
 static LONGEST
 extend_simple_arg (struct value *arg)
 {
-  struct type *type = VALUE_TYPE (arg);
+  struct type *type = value_type (arg);
 
   /* Even structs get passed in the least significant bits of the
      register / memory word.  It's not really right to extract them as
      an integer, but it does take care of the extension.  */
   if (TYPE_UNSIGNED (type))
-    return extract_unsigned_integer (VALUE_CONTENTS (arg),
+    return extract_unsigned_integer (value_contents (arg),
                                      TYPE_LENGTH (type));
   else
-    return extract_signed_integer (VALUE_CONTENTS (arg),
+    return extract_signed_integer (value_contents (arg),
                                    TYPE_LENGTH (type));
 }
 
@@ -2509,7 +1973,7 @@ alignment_of (struct type *type)
    Our caller has taken care of any type promotions needed to satisfy
    prototypes or the old K&R argument-passing rules.  */
 static CORE_ADDR
-s390_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                      struct regcache *regcache, CORE_ADDR bp_addr,
                      int nargs, struct value **args, CORE_ADDR sp,
                      int struct_return, CORE_ADDR struct_addr)
@@ -2527,14 +1991,14 @@ s390_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
   for (i = 0; i < nargs; i++)
     {
       struct value *arg = args[i];
-      struct type *type = VALUE_TYPE (arg);
+      struct type *type = value_type (arg);
       unsigned length = TYPE_LENGTH (type);
 
       if (s390_function_arg_pass_by_reference (type))
         {
           sp -= length;
           sp = align_down (sp, alignment_of (type));
-          write_memory (sp, VALUE_CONTENTS (arg), length);
+          write_memory (sp, value_contents (arg), length);
           copy_addr[i] = sp;
         }
     }
@@ -2568,7 +2032,7 @@ s390_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
     for (i = 0; i < nargs; i++)
       {
         struct value *arg = args[i];
-        struct type *type = VALUE_TYPE (arg);
+        struct type *type = value_type (arg);
         unsigned length = TYPE_LENGTH (type);
 
        if (s390_function_arg_pass_by_reference (type))
@@ -2594,7 +2058,7 @@ s390_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
                /* When we store a single-precision value in an FP register,
                   it occupies the leftmost bits.  */
                regcache_cooked_write_part (regcache, S390_F0_REGNUM + fr,
-                                           0, length, VALUE_CONTENTS (arg));
+                                           0, length, value_contents (arg));
                fr += 2;
              }
            else
@@ -2602,7 +2066,7 @@ s390_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
                /* When we store a single-precision value in a stack slot,
                   it occupies the rightmost bits.  */
                starg = align_up (starg + length, word_size);
-                write_memory (starg - length, VALUE_CONTENTS (arg), length);
+                write_memory (starg - length, value_contents (arg), length);
              }
          }
        else if (s390_function_arg_integer (type) && length <= word_size)
@@ -2627,9 +2091,9 @@ s390_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
            if (gr <= 5)
              {
                regcache_cooked_write (regcache, S390_R0_REGNUM + gr,
-                                      VALUE_CONTENTS (arg));
+                                      value_contents (arg));
                regcache_cooked_write (regcache, S390_R0_REGNUM + gr + 1,
-                                      VALUE_CONTENTS (arg) + word_size);
+                                      value_contents (arg) + word_size);
                gr += 2;
              }
            else
@@ -2638,12 +2102,12 @@ s390_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
                   in it, then don't go back and use it again later.  */
                gr = 7;
 
-               write_memory (starg, VALUE_CONTENTS (arg), length);
+               write_memory (starg, value_contents (arg), length);
                starg += length;
              }
          }
        else
-         internal_error (__FILE__, __LINE__, "unknown argument type");
+         internal_error (__FILE__, __LINE__, _("unknown argument type"));
       }
   }
 
@@ -2652,11 +2116,6 @@ s390_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
      and the back chain pointer.  */
   sp -= 16*word_size + 32;
 
-  /* Write the back chain pointer into the first word of the stack
-     frame.  This is needed to unwind across a dummy frame.  */
-  regcache_cooked_read_unsigned (regcache, S390_SP_REGNUM, &orig_sp);
-  write_memory_unsigned_integer (sp, word_size, orig_sp);
-
   /* Store return address.  */
   regcache_cooked_write_unsigned (regcache, S390_RETADDR_REGNUM, bp_addr);
   
@@ -2664,9 +2123,8 @@ s390_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
   regcache_cooked_write_unsigned (regcache, S390_SP_REGNUM, sp);
 
   /* We need to return the 'stack part' of the frame ID,
-     which is actually the top of the register save area
-     allocated on the original stack.  */
-  return orig_sp + 16*word_size + 32;
+     which is actually the top of the register save area.  */
+  return sp + 16*word_size + 32;
 }
 
 /* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
@@ -2677,10 +2135,9 @@ static struct frame_id
 s390_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
   int word_size = gdbarch_ptr_bit (gdbarch) / 8;
-  CORE_ADDR this_sp = s390_unwind_sp (gdbarch, next_frame);
-  CORE_ADDR prev_sp = read_memory_unsigned_integer (this_sp, word_size);
+  CORE_ADDR sp = s390_unwind_sp (gdbarch, next_frame);
 
-  return frame_id_build (prev_sp + 16*word_size + 32,
+  return frame_id_build (sp + 16*word_size + 32,
                          frame_pc_unwind (next_frame));
 }
 
@@ -2716,7 +2173,8 @@ s390_return_value_convention (struct gdbarch *gdbarch, struct type *type)
 
 static enum return_value_convention
 s390_return_value (struct gdbarch *gdbarch, struct type *type, 
-                  struct regcache *regcache, void *out, const void *in)
+                  struct regcache *regcache, gdb_byte *out,
+                  const gdb_byte *in)
 {
   int word_size = gdbarch_ptr_bit (gdbarch) / 8;
   int length = TYPE_LENGTH (type);
@@ -2747,15 +2205,14 @@ s390_return_value (struct gdbarch *gdbarch, struct type *type,
          else if (length == 2*word_size)
            {
              regcache_cooked_write (regcache, S390_R2_REGNUM, in);
-             regcache_cooked_write (regcache, S390_R3_REGNUM,
-                                    (const char *)in + word_size);
+             regcache_cooked_write (regcache, S390_R3_REGNUM, in + word_size);
            }
          else
-           internal_error (__FILE__, __LINE__, "invalid return type");
+           internal_error (__FILE__, __LINE__, _("invalid return type"));
          break;
 
        case RETURN_VALUE_STRUCT_CONVENTION:
-         error ("Cannot set function return value.");
+         error (_("Cannot set function return value."));
          break;
        }
     }
@@ -2780,15 +2237,14 @@ s390_return_value (struct gdbarch *gdbarch, struct type *type,
          else if (length == 2*word_size)
            {
              regcache_cooked_read (regcache, S390_R2_REGNUM, out);
-             regcache_cooked_read (regcache, S390_R3_REGNUM,
-                                   (char *)out + word_size);
+             regcache_cooked_read (regcache, S390_R3_REGNUM, out + word_size);
            }
          else
-           internal_error (__FILE__, __LINE__, "invalid return type");
+           internal_error (__FILE__, __LINE__, _("invalid return type"));
          break;
 
        case RETURN_VALUE_STRUCT_CONVENTION:
-         error ("Function return value unknown.");
+         error (_("Function return value unknown."));
          break;
        }
     }
@@ -2799,10 +2255,10 @@ s390_return_value (struct gdbarch *gdbarch, struct type *type,
 
 /* Breakpoints.  */
 
-static const unsigned char *
+static const gdb_byte *
 s390_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
 {
-  static unsigned char breakpoint[] = { 0x0, 0x1 };
+  static const gdb_byte breakpoint[] = { 0x0, 0x1 };
 
   *lenptr = sizeof (breakpoint);
   return breakpoint;
@@ -2848,76 +2304,6 @@ s390_address_class_name_to_type_flags (struct gdbarch *gdbarch, const char *name
     return 0;
 }
 
-
-/* Link map offsets.  */
-
-static struct link_map_offsets *
-s390_svr4_fetch_link_map_offsets (void)
-{
-  static struct link_map_offsets lmo;
-  static struct link_map_offsets *lmp = NULL;
-
-  if (lmp == NULL)
-    {
-      lmp = &lmo;
-
-      lmo.r_debug_size = 8;
-
-      lmo.r_map_offset = 4;
-      lmo.r_map_size   = 4;
-
-      lmo.link_map_size = 20;
-
-      lmo.l_addr_offset = 0;
-      lmo.l_addr_size   = 4;
-
-      lmo.l_name_offset = 4;
-      lmo.l_name_size   = 4;
-
-      lmo.l_next_offset = 12;
-      lmo.l_next_size   = 4;
-
-      lmo.l_prev_offset = 16;
-      lmo.l_prev_size   = 4;
-    }
-
-  return lmp;
-}
-
-static struct link_map_offsets *
-s390x_svr4_fetch_link_map_offsets (void)
-{
-  static struct link_map_offsets lmo;
-  static struct link_map_offsets *lmp = NULL;
-
-  if (lmp == NULL)
-    {
-      lmp = &lmo;
-
-      lmo.r_debug_size = 16;   /* All we need.  */
-
-      lmo.r_map_offset = 8;
-      lmo.r_map_size   = 8;
-
-      lmo.link_map_size = 40;   /* All we need.  */
-
-      lmo.l_addr_offset = 0;
-      lmo.l_addr_size   = 8;
-
-      lmo.l_name_offset = 8;
-      lmo.l_name_size   = 8;
-
-      lmo.l_next_offset = 24;
-      lmo.l_next_size   = 8;
-
-      lmo.l_prev_offset = 32;
-      lmo.l_prev_size   = 8;
-    }
-
-  return lmp;
-}
-
-
 /* Set up gdbarch struct.  */
 
 static struct gdbarch *
@@ -2943,7 +2329,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_char_signed (gdbarch, 0);
 
   /* Amount PC must be decremented by after a breakpoint.  This is
-     often the number of bytes returned by BREAKPOINT_FROM_PC but not
+     often the number of bytes returned by gdbarch_breakpoint_from_pc but not
      always.  */
   set_gdbarch_decr_pc_after_break (gdbarch, 2);
   /* Stack grows downward.  */
@@ -2962,9 +2348,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_stab_reg_to_regnum (gdbarch, s390_dwarf_reg_to_regnum);
   set_gdbarch_dwarf_reg_to_regnum (gdbarch, s390_dwarf_reg_to_regnum);
   set_gdbarch_dwarf2_reg_to_regnum (gdbarch, s390_dwarf_reg_to_regnum);
-  set_gdbarch_convert_register_p (gdbarch, s390_convert_register_p);
-  set_gdbarch_register_to_value (gdbarch, s390_register_to_value);
-  set_gdbarch_value_to_register (gdbarch, s390_value_to_register);
+  set_gdbarch_value_from_register (gdbarch, s390_value_from_register);
   set_gdbarch_register_reggroup_p (gdbarch, s390_register_reggroup_p);
   set_gdbarch_regset_from_core_section (gdbarch,
                                         s390_regset_from_core_section);
@@ -2976,8 +2360,10 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_return_value (gdbarch, s390_return_value);
 
   /* Frame handling.  */
-  set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
-  frame_unwind_append_sniffer (gdbarch, s390_pltstub_frame_sniffer);
+  dwarf2_frame_set_init_reg (gdbarch, s390_dwarf2_frame_init_reg);
+  frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+  frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
+  frame_unwind_append_sniffer (gdbarch, s390_stub_frame_sniffer);
   frame_unwind_append_sniffer (gdbarch, s390_sigtramp_frame_sniffer);
   frame_unwind_append_sniffer (gdbarch, s390_frame_sniffer);
   frame_base_set_default (gdbarch, &s390_frame_base);
@@ -2997,8 +2383,8 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       set_gdbarch_addr_bits_remove (gdbarch, s390_addr_bits_remove);
       set_gdbarch_pseudo_register_read (gdbarch, s390_pseudo_register_read);
       set_gdbarch_pseudo_register_write (gdbarch, s390_pseudo_register_write);
-      set_solib_svr4_fetch_link_map_offsets (gdbarch,
-                                            s390_svr4_fetch_link_map_offsets);
+      set_solib_svr4_fetch_link_map_offsets
+       (gdbarch, svr4_ilp32_fetch_link_map_offsets);
 
       break;
     case bfd_mach_s390_64:
@@ -3014,8 +2400,8 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       set_gdbarch_ptr_bit (gdbarch, 64);
       set_gdbarch_pseudo_register_read (gdbarch, s390x_pseudo_register_read);
       set_gdbarch_pseudo_register_write (gdbarch, s390x_pseudo_register_write);
-      set_solib_svr4_fetch_link_map_offsets (gdbarch,
-                                            s390x_svr4_fetch_link_map_offsets);
+      set_solib_svr4_fetch_link_map_offsets
+       (gdbarch, svr4_lp64_fetch_link_map_offsets);
       set_gdbarch_address_class_type_flags (gdbarch,
                                             s390_address_class_type_flags);
       set_gdbarch_address_class_type_flags_to_name (gdbarch,
@@ -3027,6 +2413,12 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   set_gdbarch_print_insn (gdbarch, print_insn_s390);
 
+  set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+
+  /* Enable TLS support.  */
+  set_gdbarch_fetch_tls_load_module_address (gdbarch,
+                                             svr4_fetch_objfile_link_map);
+
   return gdbarch;
 }