2002-01-23 Elena Zannoni <ezannoni@redhat.com>
[deliverable/binutils-gdb.git] / gdb / s390-tdep.c
index be50a9224633a9966ceea544214a2b2762a89fe4..239b17a33da12d4530dfc4658b3fd7e534baa02d 100644 (file)
 
 
 /* Number of bytes of storage in the actual machine representation
-   for register N. 
-   Note that the unsigned cast here forces the result of the
-   subtraction to very high positive values if N < S390_FP0_REGNUM */
+   for register N.  */
 int
 s390_register_raw_size (int reg_nr)
 {
-  return ((unsigned) reg_nr - S390_FP0_REGNUM) <
-    S390_NUM_FPRS ? S390_FPR_SIZE : 4;
+  if (S390_FP0_REGNUM <= reg_nr
+      && reg_nr < S390_FP0_REGNUM + S390_NUM_FPRS)
+    return S390_FPR_SIZE;
+  else
+    return 4;
 }
 
 int
@@ -131,8 +132,11 @@ s390_readinstruction (bfd_byte instr[], CORE_ADDR at,
   if ((*info->read_memory_func) (at, &instr[0], 2, info))
     return -1;
   instrlen = s390_instrlen[instr[0] >> 6];
-  if ((*info->read_memory_func) (at + 2, &instr[2], instrlen - 2, info))
-    return -1;
+  if (instrlen > 2)
+    {
+      if ((*info->read_memory_func) (at + 2, &instr[2], instrlen - 2, info))
+        return -1;
+    }
   return instrlen;
 }
 
@@ -160,9 +164,10 @@ s390_register_name (int reg_nr)
     "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15"
   };
 
-  if (reg_nr >= S390_LAST_REGNUM)
+  if (reg_nr <= S390_LAST_REGNUM)
+    return register_names[reg_nr];
+  else
     return NULL;
-  return register_names[reg_nr];
 }
 
 
@@ -180,6 +185,14 @@ s390_stab_reg_to_regnum (int regno)
 }
 
 
+/* Return true if REGIDX is the number of a register used to pass
+     arguments, false otherwise.  */
+static int
+is_arg_reg (int regidx)
+{
+  return 2 <= regidx && regidx <= 6;
+}
+
 
 /* s390_get_frame_info based on Hartmuts
    prologue definition in
@@ -208,15 +221,45 @@ s390_get_frame_info (CORE_ADDR pc, struct frame_extra_info *fextra_info,
   int gprs_saved[S390_NUM_GPRS];
   int fprs_saved[S390_NUM_FPRS];
   int regidx, instrlen;
-  int save_link_regidx, subtract_sp_regidx;
-  int const_pool_state, save_link_state;
-  int frame_pointer_found, varargs_state;
+  int const_pool_state;
+  int varargs_state;
   int loop_cnt, gdb_gpr_store, gdb_fpr_store;
-  int frame_pointer_regidx = 0xf;
   int offset, expected_offset;
   int err = 0;
   disassemble_info info;
 
+  /* Have we seen an instruction initializing the frame pointer yet?
+     If we've seen an `lr %r11, %r15', then frame_pointer_found is
+     non-zero, and frame_pointer_regidx == 11.  Otherwise,
+     frame_pointer_found is zero and frame_pointer_regidx is 15,
+     indicating that we're using the stack pointer as our frame
+     pointer.  */
+  int frame_pointer_found = 0;
+  int frame_pointer_regidx = 0xf;
+
+  /* What we've seen so far regarding saving the back chain link:
+     0 -- nothing yet; sp still has the same value it had at the entry
+          point.  Since not all functions allocate frames, this is a
+          valid state for the prologue to finish in.
+     1 -- We've saved the original sp in some register other than the
+          frame pointer (hard-coded to be %r11, yuck).
+          save_link_regidx is the register we saved it in.
+     2 -- We've seen the initial `bras' instruction of the sequence for
+          reserving more than 32k of stack:
+                bras %rX, .+8
+                .long N
+                s %r15, 0(%rX)
+          where %rX is not the constant pool register.
+          subtract_sp_regidx is %rX, and fextra_info->stack_bought is N.
+     3 -- We've reserved space for a new stack frame.  This means we
+          either saw a simple `ahi %r15,-N' in state 1, or the final
+          `s %r15, ...' in state 2.
+     4 -- The frame and link are now fully initialized.  We've
+          reserved space for the new stack frame, and stored the old
+          stack pointer captured in the back chain pointer field.  */
+  int save_link_state = 0;
+  int save_link_regidx, subtract_sp_regidx;
+
   /* What we've seen so far regarding r12 --- the GOT (Global Offset
      Table) pointer.  We expect to see `l %r12, N(%r13)', which loads
      r12 with the offset from the constant pool to the GOT, and then
@@ -228,11 +271,11 @@ s390_get_frame_info (CORE_ADDR pc, struct frame_extra_info *fextra_info,
      When got_state is 1, then got_load_addr is the address of the
      load instruction, and got_load_len is the length of that
      instruction.  */
-  int got_state;
+  int got_state= 0;
   CORE_ADDR got_load_addr = 0, got_load_len = 0;
 
-  const_pool_state = save_link_state = got_state = varargs_state = 0;
-  frame_pointer_found = 0;
+  const_pool_state = varargs_state = 0;
+
   memset (gprs_saved, 0, sizeof (gprs_saved));
   memset (fprs_saved, 0, sizeof (fprs_saved));
   info.read_memory_func = dis_asm_read_memory;
@@ -242,7 +285,9 @@ s390_get_frame_info (CORE_ADDR pc, struct frame_extra_info *fextra_info,
     {
       if (fi && fi->frame)
        {
-         orig_sp = fi->frame + fextra_info->stack_bought;
+          orig_sp = fi->frame;
+          if (! init_extra_info && fextra_info->initialised)
+            orig_sp += fextra_info->stack_bought;
          saved_regs = fi->saved_regs;
        }
       if (init_extra_info || !fextra_info->initialised)
@@ -374,6 +419,28 @@ s390_get_frame_info (CORE_ADDR pc, struct frame_extra_info *fextra_info,
          continue;
        }
 
+      /* Check for an fp-relative STG, ST, or STM.  This is probably
+          spilling an argument from a register out into a stack slot.
+          This could be a user instruction, but if we haven't included
+          any other suspicious instructions in the prologue, this
+          could only be an initializing store, which isn't too bad to
+          skip.  The consequences of not including arg-to-stack spills
+          are more serious, though --- you don't see the proper values
+          of the arguments.  */
+      if ((save_link_state == 3 || save_link_state == 4)
+          && ((instr[0] == 0x50      /* st %rA, D(%rX,%rB) */
+               && (instr[1] & 0xf) == 0 /* %rX is zero, no index reg */
+               && is_arg_reg ((instr[1] >> 4) & 0xf)
+               && ((instr[2] >> 4) & 0xf) == frame_pointer_regidx)
+              || (instr[0] == 0x90 /* stm %rA, %rB, D(%rC) */
+                  && is_arg_reg ((instr[1] >> 4) & 0xf)
+                  && is_arg_reg (instr[1] & 0xf)
+                  && ((instr[2] >> 4) & 0xf) == frame_pointer_regidx)))
+        {
+          valid_prologue = 1;
+          continue;
+        }
+
       /* check for STD */
       if (instr[0] == 0x60 && (instr[2] >> 4) == 0xf)
        {
@@ -492,7 +559,8 @@ s390_get_frame_info (CORE_ADDR pc, struct frame_extra_info *fextra_info,
       /* Alternatively check for the complex construction for
          buying more than 32k of stack
          BRAS gprx,.+8
-         long vals    %r15,0(%gprx)  gprx currently r1 */
+         long val
+         s    %r15,0(%gprx)  gprx currently r1 */
       if ((save_link_state == 1) && (instr[0] == 0xa7)
          && ((instr[1] & 0xf) == 0x5) && (instr[2] == 0)
          && (instr[3] == 0x4) && ((instr[1] >> 4) != CONST_POOL_REGIDX))
@@ -884,20 +952,24 @@ s390_frame_saved_pc_nofix (struct frame_info *fi)
 {
   if (fi->extra_info && fi->extra_info->saved_pc_valid)
     return fi->extra_info->saved_pc;
+
+  if (generic_find_dummy_frame (fi->pc, fi->frame))
+    return generic_read_register_dummy (fi->pc, fi->frame, S390_PC_REGNUM);
+
   s390_frame_init_saved_regs (fi);
   if (fi->extra_info)
     {
       fi->extra_info->saved_pc_valid = 1;
-      if (fi->extra_info->good_prologue)
-       {
-         if (fi->saved_regs[S390_RETADDR_REGNUM])
-           {
-             return (fi->extra_info->saved_pc =
-                     ADDR_BITS_REMOVE (read_memory_integer
-                                       (fi->saved_regs[S390_RETADDR_REGNUM],
-                                        S390_GPR_SIZE)));
-           }
-       }
+      if (fi->extra_info->good_prologue
+          && fi->saved_regs[S390_RETADDR_REGNUM])
+        fi->extra_info->saved_pc
+          = ADDR_BITS_REMOVE (read_memory_integer
+                              (fi->saved_regs[S390_RETADDR_REGNUM],
+                               S390_GPR_SIZE));
+      else
+        fi->extra_info->saved_pc
+          = ADDR_BITS_REMOVE (read_register (S390_RETADDR_REGNUM));
+      return fi->extra_info->saved_pc;
     }
   return 0;
 }
@@ -937,6 +1009,9 @@ s390_frame_chain (struct frame_info *thisframe)
 
   if (thisframe->prev && thisframe->prev->frame)
     prev_fp = thisframe->prev->frame;
+  else if (generic_find_dummy_frame (thisframe->pc, thisframe->frame))
+    return generic_read_register_dummy (thisframe->pc, thisframe->frame,
+                                        S390_SP_REGNUM);
   else
     {
       int sigreturn = 0;
@@ -974,18 +1049,24 @@ s390_frame_chain (struct frame_info *thisframe)
        {
          if (thisframe->saved_regs)
            {
-
              int regno;
 
-             regno =
-               ((prev_fextra_info.frame_pointer_saved_pc
-                 && thisframe->
-                 saved_regs[S390_FRAME_REGNUM]) ? S390_FRAME_REGNUM :
-                S390_SP_REGNUM);
+              if (prev_fextra_info.frame_pointer_saved_pc
+                  && thisframe->saved_regs[S390_FRAME_REGNUM])
+                regno = S390_FRAME_REGNUM;
+              else
+                regno = S390_SP_REGNUM;
+
              if (thisframe->saved_regs[regno])
-               prev_fp =
-                 read_memory_integer (thisframe->saved_regs[regno],
-                                      S390_GPR_SIZE);
+                {
+                  /* The SP's entry of `saved_regs' is special.  */
+                  if (regno == S390_SP_REGNUM)
+                    prev_fp = thisframe->saved_regs[regno];
+                  else
+                    prev_fp =
+                      read_memory_integer (thisframe->saved_regs[regno],
+                                           S390_GPR_SIZE);
+                }
            }
        }
     }
@@ -1067,12 +1148,13 @@ s390_store_return_value (struct type *valtype, char *valbuf)
 
   if (TYPE_CODE (valtype) == TYPE_CODE_FLT)
     {
-      DOUBLEST tempfloat = extract_floating (valbuf, TYPE_LENGTH (valtype));
-
-      floatformat_from_doublest (&floatformat_ieee_double_big, &tempfloat,
-                                reg_buff);
-      write_register_bytes (REGISTER_BYTE (S390_FP0_REGNUM), reg_buff,
-                           S390_FPR_SIZE);
+      if (TYPE_LENGTH (valtype) == 4
+          || TYPE_LENGTH (valtype) == 8)
+        write_register_bytes (REGISTER_BYTE (S390_FP0_REGNUM), valbuf,
+                              TYPE_LENGTH (valtype));
+      else
+        error ("GDB is unable to return `long double' values "
+               "on this architecture.");
     }
   else
     {
@@ -1143,20 +1225,23 @@ s390_pop_frame_regular (struct frame_info *frame)
   write_register (S390_PC_REGNUM, FRAME_SAVED_PC (frame));
 
   /* Restore any saved registers.  */
-  for (regnum = 0; regnum < NUM_REGS; regnum++)
-    if (frame->saved_regs[regnum] != 0)
-      {
-        ULONGEST value;
-
-        value = read_memory_unsigned_integer (frame->saved_regs[regnum],
-                                              REGISTER_RAW_SIZE (regnum));
-        write_register (regnum, value);
-      }
+  if (frame->saved_regs)
+    {
+      for (regnum = 0; regnum < NUM_REGS; regnum++)
+        if (frame->saved_regs[regnum] != 0)
+          {
+            ULONGEST value;
+            
+            value = read_memory_unsigned_integer (frame->saved_regs[regnum],
+                                                  REGISTER_RAW_SIZE (regnum));
+            write_register (regnum, value);
+          }
 
-  /* Actually cut back the stack.  Remember that the SP's element of
-     saved_regs is the old SP itself, not the address at which it is
-     saved.  */
-  write_register (S390_SP_REGNUM, frame->saved_regs[S390_SP_REGNUM]);
+      /* Actually cut back the stack.  Remember that the SP's element of
+         saved_regs is the old SP itself, not the address at which it is
+         saved.  */
+      write_register (S390_SP_REGNUM, frame->saved_regs[S390_SP_REGNUM]);
+    }
 
   /* Throw away any cached frame information.  */
   flush_cached_frames ();
@@ -1577,13 +1662,26 @@ s390_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
   return sp;
 }
 
+
+static int
+s390_use_struct_convention (int gcc_p, struct type *value_type)
+{
+  enum type_code code = TYPE_CODE (value_type);
+
+  return (code == TYPE_CODE_STRUCT
+          || code == TYPE_CODE_UNION);
+}
+
+
 /* Return the GDB type object for the "standard" data type
    of data in register N.  */
 struct type *
 s390_register_virtual_type (int regno)
 {
-  return ((unsigned) regno - S390_FPC_REGNUM) <
-    S390_NUM_FPRS ? builtin_type_double : builtin_type_int;
+  if (S390_FP0_REGNUM <= regno && regno < S390_FP0_REGNUM + S390_NUM_FPRS)
+    return builtin_type_double;
+  else
+    return builtin_type_int;
 }
 
 
@@ -1670,6 +1768,7 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   gdbarch = gdbarch_alloc (&info, NULL);
 
   set_gdbarch_believe_pcc_promotion (gdbarch, 0);
+  set_gdbarch_char_signed (gdbarch, 0);
 
   set_gdbarch_frame_args_skip (gdbarch, 0);
   set_gdbarch_frame_args_address (gdbarch, s390_frame_args_address);
@@ -1686,7 +1785,6 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
      but not always.  */
   set_gdbarch_decr_pc_after_break (gdbarch, 2);
   set_gdbarch_pop_frame (gdbarch, s390_pop_frame);
-  set_gdbarch_ieee_float (gdbarch, 1);
   /* Stack grows downward.  */
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
   /* Offset from address of function to start of its code.
@@ -1720,12 +1818,14 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_cannot_fetch_register (gdbarch, s390_cannot_fetch_register);
   set_gdbarch_cannot_store_register (gdbarch, s390_cannot_fetch_register);
   set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register);
-  set_gdbarch_use_struct_convention (gdbarch, generic_use_struct_convention);
+  set_gdbarch_use_struct_convention (gdbarch, s390_use_struct_convention);
   set_gdbarch_frame_chain_valid (gdbarch, func_frame_chain_valid);
   set_gdbarch_register_name (gdbarch, s390_register_name);
   set_gdbarch_stab_reg_to_regnum (gdbarch, s390_stab_reg_to_regnum);
   set_gdbarch_dwarf_reg_to_regnum (gdbarch, s390_stab_reg_to_regnum);
   set_gdbarch_dwarf2_reg_to_regnum (gdbarch, s390_stab_reg_to_regnum);
+  set_gdbarch_extract_struct_value_address
+    (gdbarch, generic_cannot_extract_struct_value_address);
 
   /* Parameters for inferior function calls.  */
   set_gdbarch_call_dummy_p (gdbarch, 1);
@@ -1737,10 +1837,10 @@ s390_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_at_entry_point);
   set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
   set_gdbarch_push_arguments (gdbarch, s390_push_arguments);
+  set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
   set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
   set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
   set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
-  set_gdbarch_extract_struct_value_address (gdbarch, 0);
   set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy);
   set_gdbarch_push_return_address (gdbarch, s390_push_return_address);
   set_gdbarch_sizeof_call_dummy_words (gdbarch,
This page took 0.045601 seconds and 4 git commands to generate.