* s390-tdep.c (enum pv_boolean): Remove.
authorUlrich Weigand <uweigand@de.ibm.com>
Sat, 23 Oct 2004 16:31:23 +0000 (16:31 +0000)
committerUlrich Weigand <uweigand@de.ibm.com>
Sat, 23 Oct 2004 16:31:23 +0000 (16:31 +0000)
(pv_is_array_ref): Remove.
(s390_on_stack): Remove.
(S390_NUM_SPILL_SLOTS): Remove.
(struct s390_prologue_data): Remove members 'spill' and 'back_chain',
add members 'gpr_slot', 'fpr_slot', and 'back_chain_saved_p'.
(s390_store): Track all stores of orginal incoming registers to the
stack constant offsets relative to the CFA, instead of only tracking
stores into specific spill slots.
(s390_load): Likewise.
(s390_analyze_prologue): Adapt to struct s390_prologue_data changes.
(s390_prologue_frame_unwind_cache): Likewise.  Only track registers
defined as call-saved by the ABI.
(s390_push_dummy_call): Use bottom of dummy call argument save area
as return value, not the top.  Do not store to the called function's
register save area.
(s390_unwind_dummy_id): Adapt accordingly.

gdb/ChangeLog
gdb/s390-tdep.c

index 5120f9ee9947defbd832222c1a8d1641c27ff1e4..12485fa0ef702f512f83bb8dce942fc99018bc6e 100644 (file)
@@ -1,3 +1,23 @@
+2004-10-23  Ulrich Weigand  <uweigand@de.ibm.com>
+
+       * s390-tdep.c (enum pv_boolean): Remove.
+       (pv_is_array_ref): Remove.
+       (s390_on_stack): Remove.
+       (S390_NUM_SPILL_SLOTS): Remove.
+       (struct s390_prologue_data): Remove members 'spill' and 'back_chain',
+       add members 'gpr_slot', 'fpr_slot', and 'back_chain_saved_p'.
+       (s390_store): Track all stores of orginal incoming registers to the
+       stack constant offsets relative to the CFA, instead of only tracking
+       stores into specific spill slots.
+       (s390_load): Likewise.
+       (s390_analyze_prologue): Adapt to struct s390_prologue_data changes.
+       (s390_prologue_frame_unwind_cache): Likewise.  Only track registers
+       defined as call-saved by the ABI.
+       (s390_push_dummy_call): Use bottom of dummy call argument save area
+       as return value, not the top.  Do not store to the called function's
+       register save area.
+       (s390_unwind_dummy_id): Adapt accordingly.
+
 2004-10-23  Andrew Cagney  <cagney@gnu.org>
 
        * objfiles.h (struct objfile): Rename obj_private to
index 055ba6cf684c2d73511731a8d5772f9a86510635..8245fa4b0c8823dd7775efa5b0f83e4d14824168 100644 (file)
@@ -801,66 +801,6 @@ pv_is_register (struct prologue_value *a, int r, CORE_ADDR 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
@@ -1116,10 +1056,6 @@ compute_x_addr (struct prologue_value *addr,
 }
 
 
-/* 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
 
@@ -1135,83 +1071,17 @@ struct s390_prologue_data {
   /* 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;
-};
+  /* 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];
 
+  /* Likewise for FPRs.  */
+  int fpr_slot[S390_NUM_FPRS];
 
-/* 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.
-
-   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;
-
-  /* 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];
-
-  /* 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.)  */
-
-  /* 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;
-
-  /* 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;
-
-  /* All the above queries returned definite 'no's.  */
-  return pv_definite_no;
-}
-
+  /* 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;
+};
 
 /* Do a SIZE-byte store of VALUE to ADDR.  */
 static void
@@ -1220,22 +1090,61 @@ s390_store (struct prologue_value *addr,
             struct prologue_value *value,
            struct s390_prologue_data *data)
 {
-  struct prologue_value *stack;
+  struct prologue_value cfa, offset;
+  int i;
 
-  /* 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)
+  /* Check whether we are storing the backchain.  */
+  pv_subtract (&offset, &data->gpr[S390_SP_REGNUM - S390_R0_REGNUM], addr);
+
+  if (offset.kind == pv_constant && offset.k == 0)
+    if (size == data->gpr_size
+       && pv_is_register (value, S390_SP_REGNUM, 0))
+      {
+       data->back_chain_saved_p = 1;
+       return;
+      }
+
+
+  /* Check whether we are storing a register into the stack.  */
+  pv_set_to_register (&cfa, S390_SP_REGNUM, 16 * data->gpr_size + 32);
+  pv_subtract (&offset, &cfa, addr);
+
+  if (offset.kind == pv_constant
+      && offset.k < INT_MAX && offset.k > 0
+      && offset.k % data->gpr_size == 0)
     {
-      *stack = *value;
-      return;
+      /* 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 (value, S390_R0_REGNUM + i, 0))
+         if (data->gpr_slot[i] == 0
+             || data->gpr_slot[i] > offset.k)
+           {
+             data->gpr_slot[i] = offset.k;
+             return;
+           }
+
+      for (i = 0; i < S390_NUM_FPRS; i++)
+       if (size == data->fpr_size
+           && pv_is_register (value, S390_F0_REGNUM + i, 0))
+         if (data->fpr_slot[i] == 0
+             || data->fpr_slot[i] > offset.k)
+           {
+             data->fpr_slot[i] = offset.k;
+             return;
+           }
     }
 
-  /* 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.  */
@@ -1245,7 +1154,8 @@ s390_load (struct prologue_value *addr,
           struct prologue_value *value,
           struct s390_prologue_data *data)
 {
-  struct prologue_value *stack;
+  struct prologue_value cfa, offset;
+  int i;
 
   /* If it's a load from an in-line constant pool, then we can
      simulate that, under the assumption that the code isn't
@@ -1265,12 +1175,26 @@ s390_load (struct prologue_value *addr,
        }
     }
 
-  /* 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)
+  /* Check whether we are accessing one of our save slots.  */
+  pv_set_to_register (&cfa, S390_SP_REGNUM, 16 * data->gpr_size + 32);
+  pv_subtract (&offset, &cfa, addr);
+
+  if (offset.kind == pv_constant
+      && offset.k < INT_MAX && offset.k > 0)
     {
-      *value = *stack;
-      return;
+      for (i = 0; i < S390_NUM_GPRS; i++)
+       if (offset.k == data->gpr_slot[i])
+         {
+           pv_set_to_register (value, S390_R0_REGNUM + i, 0);
+           return;
+         }
+
+      for (i = 0; i < S390_NUM_FPRS; i++)
+       if (offset.k == data->fpr_slot[i])
+         {
+           pv_set_to_register (value, S390_F0_REGNUM + i, 0);
+           return;
+         }
     }
 
   /* Otherwise, we don't know the value.  */
@@ -1320,10 +1244,13 @@ s390_analyze_prologue (struct gdbarch *gdbarch,
     for (i = 0; i < S390_NUM_FPRS; i++)
       pv_set_to_register (&data->fpr[i], 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
@@ -1337,9 +1264,11 @@ s390_analyze_prologue (struct gdbarch *gdbarch,
       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;
+      struct prologue_value 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)
@@ -1352,7 +1281,7 @@ 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;
+      pre_insn_back_chain_saved_p = data->back_chain_saved_p;
 
       /* LHI r1, i2 --- load halfword immediate */
       if (word_size == 4
@@ -1674,7 +1603,7 @@ s390_analyze_prologue (struct gdbarch *gdbarch,
              && ! 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))
+            || pre_insn_back_chain_saved_p != data->back_chain_saved_p)
           result = next_pc;
       }
     }
@@ -1761,12 +1690,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;
+  int i;
+  CORE_ADDR cfa;
   CORE_ADDR func;
   CORE_ADDR result;
   ULONGEST reg;
@@ -1869,33 +1799,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.  */
-
-  /* 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];
+  /* 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.  */
 
-      if (slot->kind == pv_register
-          && slot->k == 0)
-        info->saved_regs[slot->reg].addr = slot_addr;
-    }
+  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];
 
-  /* 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.  */
@@ -2708,11 +2636,6 @@ s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
      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);
   
@@ -2720,9 +2643,8 @@ s390_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
   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
@@ -2733,10 +2655,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));
 }