2004-02-14 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / gdb / sh-tdep.c
index 60fe4b611ca4db8f7bcfc2ef734720569c44d587..1db65c66c5df602c27d2e50bf4290a3485d9239d 100644 (file)
@@ -1,4 +1,4 @@
-/* Target-dependent code for Hitachi Super-H, for GDB.
+/* Target-dependent code for Renesas Super-H, for GDB.
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
 
@@ -212,8 +212,8 @@ sh_sh3_dsp_register_name (int reg_nr)
     "y0", "y1", "", "", "", "", "", "mod",
     "ssr", "spc",
     "rs", "re", "", "", "", "", "", "",
-    "r0b", "r1b", "r2b", "r3b", "r4b", "r5b", "r6b", "r7b"
-      "", "", "", "", "", "", "", "",
+    "r0b", "r1b", "r2b", "r3b", "r4b", "r5b", "r6b", "r7b",
+    "", "", "", "", "", "", "", "",
   };
   if (reg_nr < 0)
     return NULL;
@@ -256,6 +256,60 @@ sh_sh4_register_name (int reg_nr)
   return register_names[reg_nr];
 }
 
+static const char *
+sh_sh4_nofpu_register_name (int reg_nr)
+{
+  static char *register_names[] = {
+    /* general registers 0-15 */
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+    /* 16 - 22 */
+    "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
+    /* 23, 24 */
+    "", "",
+    /* floating point registers 25 - 40 -- not for nofpu target */
+    "", "", "", "", "", "", "", "",
+    "", "", "", "", "", "", "", "",
+    /* 41, 42 */
+    "ssr", "spc",
+    /* bank 0 43 - 50 */
+    "r0b0", "r1b0", "r2b0", "r3b0", "r4b0", "r5b0", "r6b0", "r7b0",
+    /* bank 1 51 - 58 */
+    "r0b1", "r1b1", "r2b1", "r3b1", "r4b1", "r5b1", "r6b1", "r7b1",
+    /* double precision (pseudo) 59 - 66 -- not for nofpu target */
+    "", "", "", "", "", "", "", "",
+    /* vectors (pseudo) 67 - 70 -- not for nofpu target */
+    "", "", "", "",
+  };
+  if (reg_nr < 0)
+    return NULL;
+  if (reg_nr >= (sizeof (register_names) / sizeof (*register_names)))
+    return NULL;
+  return register_names[reg_nr];
+}
+
+static const char *
+sh_sh4al_dsp_register_name (int reg_nr)
+{
+  static char *register_names[] = {
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+    "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
+    "", "dsr",
+    "a0g", "a0", "a1g", "a1", "m0", "m1", "x0", "x1",
+    "y0", "y1", "", "", "", "", "", "mod",
+    "ssr", "spc",
+    "rs", "re", "", "", "", "", "", "",
+    "r0b", "r1b", "r2b", "r3b", "r4b", "r5b", "r6b", "r7b",
+    "", "", "", "", "", "", "", "",
+  };
+  if (reg_nr < 0)
+    return NULL;
+  if (reg_nr >= (sizeof (register_names) / sizeof (*register_names)))
+    return NULL;
+  return register_names[reg_nr];
+}
+
 static const unsigned char *
 sh_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
 {
@@ -266,22 +320,6 @@ sh_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
   return breakpoint;
 }
 
-static CORE_ADDR
-sh_push_dummy_code (struct gdbarch *gdbarch,
-                   CORE_ADDR sp, CORE_ADDR funaddr, int using_gcc,
-                   struct value **args, int nargs,
-                   struct type *value_type,
-                   CORE_ADDR *real_pc, CORE_ADDR *bp_addr)
-{
-  /* Allocate space sufficient for a breakpoint.  */
-  sp = (sp - 2) & ~1;
-  /* Store the address of that breakpoint */
-  *bp_addr = sp;
-  /* sh always starts the call at the callee's entry point.  */
-  *real_pc = funaddr;
-  return sp;
-}
-
 /* Prologue looks like
    mov.l       r14,@-r15
    sts.l       pr,@-r15
@@ -559,14 +597,84 @@ sh_skip_prologue (CORE_ADDR start_pc)
   return pc;
 }
 
-/* Should call_function allocate stack space for a struct return?  */
+/* The ABI says:
+
+   Aggregate types not bigger than 8 bytes that have the same size and
+   alignment as one of the integer scalar types are returned in the
+   same registers as the integer type they match.
+
+   For example, a 2-byte aligned structure with size 2 bytes has the
+   same size and alignment as a short int, and will be returned in R0.
+   A 4-byte aligned structure with size 8 bytes has the same size and
+   alignment as a long long int, and will be returned in R0 and R1.
+
+   When an aggregate type is returned in R0 and R1, R0 contains the
+   first four bytes of the aggregate, and R1 contains the
+   remainder. If the size of the aggregate type is not a multiple of 4
+   bytes, the aggregate is tail-padded up to a multiple of 4
+   bytes. The value of the padding is undefined. For little-endian
+   targets the padding will appear at the most significant end of the
+   last element, for big-endian targets the padding appears at the
+   least significant end of the last element.
+
+   All other aggregate types are returned by address. The caller
+   function passes the address of an area large enough to hold the
+   aggregate value in R2. The called function stores the result in
+   this location.
+
+   To reiterate, structs smaller than 8 bytes could also be returned
+   in memory, if they don't pass the "same size and alignment as an
+   integer type" rule.
+
+   For example, in
+
+   struct s { char c[3]; } wibble;
+   struct s foo(void) {  return wibble; }
+
+   the return value from foo() will be in memory, not
+   in R0, because there is no 3-byte integer type.
+
+   Similarly, in 
+
+   struct s { char c[2]; } wibble;
+   struct s foo(void) {  return wibble; }
+
+   because a struct containing two chars has alignment 1, that matches
+   type char, but size 2, that matches type short.  There's no integer
+   type that has alignment 1 and size 2, so the struct is returned in
+   memory.
+
+*/
+
 static int
 sh_use_struct_convention (int gcc_p, struct type *type)
 {
   int len = TYPE_LENGTH (type);
   int nelem = TYPE_NFIELDS (type);
-  return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) &&
-    (len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4);
+
+  /* Non-power of 2 length types and types bigger than 8 bytes (which don't
+     fit in two registers anyway) use struct convention.  */
+  if (len != 1 && len != 2 && len != 4 && len != 8)
+    return 1;
+
+  /* Scalar types and aggregate types with exactly one field are aligned
+     by definition.  They are returned in registers.  */
+  if (nelem <= 1)
+    return 0;
+
+  /* If the first field in the aggregate has the same length as the entire
+     aggregate type, the type is returned in registers.  */
+  if (TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) == len)
+    return 0;
+
+  /* If the size of the aggregate is 8 bytes and the first field is
+     of size 4 bytes its alignment is equal to long long's alignment,
+     so it's returned in registers.  */
+  if (len == 8 && TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) == 4)
+    return 0;
+
+  /* Otherwise use struct convention.  */
+  return 1;
 }
 
 /* Extract from an array REGBUF containing the (raw) register state
@@ -590,7 +698,7 @@ sh_frame_align (struct gdbarch *ignore, CORE_ADDR sp)
 /* Function: push_dummy_call (formerly push_arguments)
    Setup the function arguments for calling a function in the inferior.
 
-   On the Hitachi SH architecture, there are four registers (R4 to R7)
+   On the Renesas SH architecture, there are four registers (R4 to R7)
    which are dedicated for passing function arguments.  Up to the first
    four arguments (depending on size) may go into these registers.
    The rest go on the stack.
@@ -732,6 +840,55 @@ sh_next_flt_argreg (int len)
   return FLOAT_ARG0_REGNUM + argreg;
 }
 
+/* Helper function which figures out, if a type is treated like a float type.
+
+   The FPU ABIs have a special way how to treat types as float types.
+   Structures with exactly one member, which is of type float or double, are
+   treated exactly as the base types float or double:
+
+     struct sf {
+       float f;
+     };
+
+     struct sd {
+       double d;
+     };
+
+   are handled the same way as just
+
+     float f;
+
+     double d;
+
+   As a result, arguments of these struct types are pushed into floating point
+   registers exactly as floats or doubles, using the same decision algorithm.
+
+   The same is valid if these types are used as function return types.  The
+   above structs are returned in fr0 resp. fr0,fr1 instead of in r0, r0,r1
+   or even using struct convention as it is for other structs.  */
+
+static int
+sh_treat_as_flt_p (struct type *type)
+{
+  int len = TYPE_LENGTH (type);
+
+  /* Ordinary float types are obviously treated as float.  */
+  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+    return 1;
+  /* Otherwise non-struct types are not treated as float.  */
+  if (TYPE_CODE (type) != TYPE_CODE_STRUCT)
+    return 0;
+  /* Otherwise structs with more than one memeber are not treated as float.  */
+  if (TYPE_NFIELDS (type) != 1)
+    return 0;
+  /* Otherwise if the type of that member is float, the whole type is
+     treated as float.  */
+  if (TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_FLT)
+    return 1;
+  /* Otherwise it's not treated as float.  */
+  return 0;
+}
+
 static CORE_ADDR
 sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
                        CORE_ADDR func_addr,
@@ -743,13 +900,14 @@ sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
 {
   int stack_offset = 0;
   int argreg = ARG0_REGNUM;
-  int flt_argreg;
+  int flt_argreg = 0;
   int argnum;
   struct type *type;
   CORE_ADDR regval;
   char *val;
-  int len, reg_size;
-  int pass_on_stack;
+  int len, reg_size = 0;
+  int pass_on_stack = 0;
+  int treat_as_flt;
 
   /* first force sp to a 4-byte alignment */
   sp = sh_frame_align (gdbarch, sp);
@@ -776,43 +934,59 @@ sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
       /* Some decisions have to be made how various types are handled.
          This also differs in different ABIs. */
       pass_on_stack = 0;
-      if (len > 16)
-       pass_on_stack = 1;      /* Types bigger than 16 bytes are passed on stack. */
 
       /* Find out the next register to use for a floating point value. */
-      if (TYPE_CODE (type) == TYPE_CODE_FLT)
+      treat_as_flt = sh_treat_as_flt_p (type);
+      if (treat_as_flt)
        flt_argreg = sh_next_flt_argreg (len);
+      /* In contrast to non-FPU CPUs, arguments are never split between
+        registers and stack.  If an argument doesn't fit in the remaining
+        registers it's always pushed entirely on the stack.  */
+      else if (len > ((ARGLAST_REGNUM - argreg + 1) * 4))
+       pass_on_stack = 1;
 
       while (len > 0)
        {
-         if ((TYPE_CODE (type) == TYPE_CODE_FLT
-              && flt_argreg > FLOAT_ARGLAST_REGNUM)
-             || argreg > ARGLAST_REGNUM || pass_on_stack)
+         if ((treat_as_flt && flt_argreg > FLOAT_ARGLAST_REGNUM)
+             || (!treat_as_flt && (argreg > ARGLAST_REGNUM
+                                   || pass_on_stack)))
            {
-             /* The remainder of the data goes entirely on the stack,
-                4-byte aligned. */
+             /* The data goes entirely on the stack, 4-byte aligned. */
              reg_size = (len + 3) & ~3;
              write_memory (sp + stack_offset, val, reg_size);
              stack_offset += reg_size;
            }
-         else if (TYPE_CODE (type) == TYPE_CODE_FLT
-                  && flt_argreg <= FLOAT_ARGLAST_REGNUM)
+         else if (treat_as_flt && flt_argreg <= FLOAT_ARGLAST_REGNUM)
            {
              /* Argument goes in a float argument register.  */
              reg_size = register_size (gdbarch, flt_argreg);
              regval = extract_unsigned_integer (val, reg_size);
+             /* In little endian mode, float types taking two registers
+                (doubles on sh4, long doubles on sh2e, sh3e and sh4) must
+                be stored swapped in the argument registers.  The below
+                code first writes the first 32 bits in the next but one
+                register, increments the val and len values accordingly
+                and then proceeds as normal by writing the second 32 bits
+                into the next register. */
+             if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE
+                 && TYPE_LENGTH (type) == 2 * reg_size)
+               {
+                 regcache_cooked_write_unsigned (regcache, flt_argreg + 1,
+                                                 regval);
+                 val += reg_size;
+                 len -= reg_size;
+                 regval = extract_unsigned_integer (val, reg_size);
+               }
              regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
            }
-         else if (argreg <= ARGLAST_REGNUM)
+         else if (!treat_as_flt && argreg <= ARGLAST_REGNUM)
            {
              /* there's room in a register */
              reg_size = register_size (gdbarch, argreg);
              regval = extract_unsigned_integer (val, reg_size);
              regcache_cooked_write_unsigned (regcache, argreg++, regval);
            }
-         /* Store the value reg_size bytes at a time.  This means that things
-            larger than reg_size bytes may go partly in registers and partly
-            on the stack.  */
+         /* Store the value one register at a time or in one step on stack.  */
          len -= reg_size;
          val += reg_size;
        }
@@ -930,12 +1104,15 @@ static void
 sh3e_sh4_extract_return_value (struct type *type, struct regcache *regcache,
                               void *valbuf)
 {
-  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+  if (sh_treat_as_flt_p (type))
     {
       int len = TYPE_LENGTH (type);
       int i, regnum = FP0_REGNUM;
       for (i = 0; i < len; i += 4)
-       regcache_raw_read (regcache, regnum++, (char *) valbuf + i);
+       if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+         regcache_raw_read (regcache, regnum++, (char *) valbuf + len - 4 - i);
+       else
+         regcache_raw_read (regcache, regnum++, (char *) valbuf + i);
     }
   else
     sh_default_extract_return_value (type, regcache, valbuf);
@@ -971,7 +1148,7 @@ static void
 sh3e_sh4_store_return_value (struct type *type, struct regcache *regcache,
                             const void *valbuf)
 {
-  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+  if (sh_treat_as_flt_p (type))
     {
       int len = TYPE_LENGTH (type);
       int i, regnum = FP0_REGNUM;
@@ -1216,6 +1393,36 @@ sh4_show_regs (void)
                   (long) read_register (FP0_REGNUM + 15));
 }
 
+static void
+sh4_nofpu_show_regs (void)
+{
+  printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n",
+                  paddr (read_register (PC_REGNUM)),
+                  (long) read_register (SR_REGNUM),
+                  (long) read_register (PR_REGNUM),
+                  (long) read_register (MACH_REGNUM),
+                  (long) read_register (MACL_REGNUM));
+
+  printf_filtered ("GBR=%08lx VBR=%08lx",
+                  (long) read_register (GBR_REGNUM),
+                  (long) read_register (VBR_REGNUM));
+  printf_filtered (" SSR=%08lx SPC=%08lx",
+                  (long) read_register (SSR_REGNUM),
+                  (long) read_register (SPC_REGNUM));
+
+  printf_filtered
+    ("\nR0-R7  %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+     (long) read_register (0), (long) read_register (1),
+     (long) read_register (2), (long) read_register (3),
+     (long) read_register (4), (long) read_register (5),
+     (long) read_register (6), (long) read_register (7));
+  printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+                  (long) read_register (8), (long) read_register (9),
+                  (long) read_register (10), (long) read_register (11),
+                  (long) read_register (12), (long) read_register (13),
+                  (long) read_register (14), (long) read_register (15));
+}
+
 static void
 sh_dsp_show_regs (void)
 {
@@ -1527,8 +1734,9 @@ sh_do_fp_register (struct gdbarch *gdbarch, struct ui_file *file, int regnum)
   fprintf_filtered (file, "\t(raw 0x");
   for (j = 0; j < register_size (gdbarch, regnum); j++)
     {
-      register int idx = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? j
-       : register_size (gdbarch, regnum) - 1 - j;
+      int idx = (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+                ? j
+                : register_size (gdbarch, regnum) - 1 - j);
       fprintf_filtered (file, "%02x", (unsigned char) raw_buffer[idx]);
     }
   fprintf_filtered (file, ")");
@@ -1973,13 +2181,20 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       break;
 
     case bfd_mach_sh3_dsp:
+    case bfd_mach_sh4al_dsp:
       sh_show_regs = sh3_dsp_show_regs;
       break;
 
     case bfd_mach_sh4:
+    case bfd_mach_sh4a:
       sh_show_regs = sh4_show_regs;
       break;
 
+    case bfd_mach_sh4_nofpu:
+    case bfd_mach_sh4a_nofpu:
+      sh_show_regs = sh4_nofpu_show_regs;
+      break;
+
     case bfd_mach_sh5:
       sh_show_regs = sh64_show_regs;
       /* SH5 is handled entirely in sh64-tdep.c */
@@ -2024,18 +2239,13 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   set_gdbarch_store_return_value (gdbarch, sh_default_store_return_value);
   set_gdbarch_extract_return_value (gdbarch, sh_default_extract_return_value);
-  set_gdbarch_extract_struct_value_address (gdbarch,
-                                           sh_extract_struct_value_address);
+  set_gdbarch_deprecated_extract_struct_value_address (gdbarch, sh_extract_struct_value_address);
 
   set_gdbarch_skip_prologue (gdbarch, sh_skip_prologue);
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
-  set_gdbarch_decr_pc_after_break (gdbarch, 0);
-  set_gdbarch_function_start_offset (gdbarch, 0);
 
-  set_gdbarch_push_dummy_code (gdbarch, sh_push_dummy_code);
   set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_nofpu);
 
-  set_gdbarch_frame_args_skip (gdbarch, 0);
   set_gdbarch_frameless_function_invocation (gdbarch,
                                             frameless_look_for_prologue);
   set_gdbarch_believe_pcc_promotion (gdbarch, 1);
@@ -2099,6 +2309,7 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       break;
 
     case bfd_mach_sh4:
+    case bfd_mach_sh4a:
       set_gdbarch_register_name (gdbarch, sh_sh4_register_name);
       set_gdbarch_register_type (gdbarch, sh_sh4_register_type);
       set_gdbarch_fp0_regnum (gdbarch, 25);
@@ -2111,6 +2322,16 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
       break;
 
+    case bfd_mach_sh4_nofpu:
+    case bfd_mach_sh4a_nofpu:
+      set_gdbarch_register_name (gdbarch, sh_sh4_nofpu_register_name);
+      break;
+
+    case bfd_mach_sh4al_dsp:
+      set_gdbarch_register_name (gdbarch, sh_sh4al_dsp_register_name);
+      set_gdbarch_register_sim_regno (gdbarch, sh_dsp_register_sim_regno);
+      break;
+
     default:
       set_gdbarch_register_name (gdbarch, sh_generic_register_name);
       break;
This page took 0.030435 seconds and 4 git commands to generate.