Update copyright year range in all GDB files.
[deliverable/binutils-gdb.git] / gdb / riscv-tdep.c
index 6a55ab8b6433c242415f85466971bd1ed3a8ddc7..9b06f7c08d3552da40f6b626aaaf0e19cd14055f 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for the RISC-V architecture, for GDB.
 
-   Copyright (C) 2018 Free Software Foundation, Inc.
+   Copyright (C) 2018-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "dwarf2-frame.h"
 #include "user-regs.h"
 #include "valprint.h"
-#include "common-defs.h"
+#include "gdbsupport/common-defs.h"
 #include "opcode/riscv-opc.h"
 #include "cli/cli-decode.h"
 #include "observable.h"
 #include "prologue-value.h"
 #include "arch/riscv.h"
+#include "riscv-ravenscar-thread.h"
 
 /* The stack must be 16-byte aligned.  */
 #define SP_ALIGNMENT 16
@@ -185,7 +186,7 @@ static const struct riscv_register_feature riscv_freg_feature =
    { RISCV_FIRST_FP_REGNUM + 5, { "ft5", "f5" }, true },
    { RISCV_FIRST_FP_REGNUM + 6, { "ft6", "f6" }, true },
    { RISCV_FIRST_FP_REGNUM + 7, { "ft7", "f7" }, true },
-   { RISCV_FIRST_FP_REGNUM + 8, { "fs0", "f8", "s0" }, true },
+   { RISCV_FIRST_FP_REGNUM + 8, { "fs0", "f8" }, true },
    { RISCV_FIRST_FP_REGNUM + 9, { "fs1", "f9" }, true },
    { RISCV_FIRST_FP_REGNUM + 10, { "fa0", "f10" }, true },
    { RISCV_FIRST_FP_REGNUM + 11, { "fa1", "f11" }, true },
@@ -361,7 +362,15 @@ static unsigned int riscv_debug_gdbarch = 0;
 int
 riscv_isa_xlen (struct gdbarch *gdbarch)
 {
-  return gdbarch_tdep (gdbarch)->features.xlen;
+  return gdbarch_tdep (gdbarch)->isa_features.xlen;
+}
+
+/* See riscv-tdep.h.  */
+
+int
+riscv_abi_xlen (struct gdbarch *gdbarch)
+{
+  return gdbarch_tdep (gdbarch)->abi_features.xlen;
 }
 
 /* See riscv-tdep.h.  */
@@ -369,7 +378,15 @@ riscv_isa_xlen (struct gdbarch *gdbarch)
 int
 riscv_isa_flen (struct gdbarch *gdbarch)
 {
-  return gdbarch_tdep (gdbarch)->features.flen;
+  return gdbarch_tdep (gdbarch)->isa_features.flen;
+}
+
+/* See riscv-tdep.h.  */
+
+int
+riscv_abi_flen (struct gdbarch *gdbarch)
+{
+  return gdbarch_tdep (gdbarch)->abi_features.flen;
 }
 
 /* Return true if the target for GDBARCH has floating point hardware.  */
@@ -385,7 +402,7 @@ riscv_has_fp_regs (struct gdbarch *gdbarch)
 static bool
 riscv_has_fp_abi (struct gdbarch *gdbarch)
 {
-  return gdbarch_tdep (gdbarch)->features.hw_float_abi;
+  return gdbarch_tdep (gdbarch)->abi_features.flen > 0;
 }
 
 /* Return true if REGNO is a floating pointer register.  */
@@ -414,7 +431,15 @@ riscv_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
        unaligned_p = true;
       else
        {
-         /* Read the opcode byte to determine the instruction length.  */
+         /* Read the opcode byte to determine the instruction length.  If
+            the read fails this may be because we tried to set the
+            breakpoint at an invalid address, in this case we provide a
+            fake result which will give a breakpoint length of 4.
+            Hopefully when we try to actually insert the breakpoint we
+            will see a failure then too which will be reported to the
+            user.  */
+         if (target_read_code (*pcptr, buf, 1) == -1)
+           buf[0] = 0;
          read_code (*pcptr, buf, 1);
        }
 
@@ -635,19 +660,18 @@ riscv_print_one_register_info (struct gdbarch *gdbarch,
   fputs_filtered (name, file);
   print_spaces_filtered (value_column_1 - strlen (name), file);
 
-  TRY
+  try
     {
       val = value_of_register (regnum, frame);
       regtype = value_type (val);
     }
-  CATCH (ex, RETURN_MASK_ERROR)
+  catch (const gdb_exception_error &ex)
     {
       /* Handle failure to read a register without interrupting the entire
          'info registers' flow.  */
-      fprintf_filtered (file, "%s\n", ex.message);
+      fprintf_filtered (file, "%s\n", ex.what ());
       return;
     }
-  END_CATCH
 
   print_raw_format = (value_entirely_available (val)
                      && !value_optimized_out (val));
@@ -665,7 +689,7 @@ riscv_print_one_register_info (struct gdbarch *gdbarch,
     {
       struct value_print_options opts;
       const gdb_byte *valaddr = value_contents_for_printing (val);
-      enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (regtype));
+      enum bfd_endian byte_order = type_byte_order (regtype);
 
       get_user_print_options (&opts);
       opts.deref_ref = 1;
@@ -896,7 +920,10 @@ riscv_register_reggroup_p (struct gdbarch  *gdbarch, int regnum,
   else if (reggroup == restore_reggroup || reggroup == save_reggroup)
     {
       if (riscv_has_fp_regs (gdbarch))
-       return regnum <= RISCV_LAST_FP_REGNUM;
+       return (regnum <= RISCV_LAST_FP_REGNUM
+               || regnum == RISCV_CSR_FCSR_REGNUM
+               || regnum == RISCV_CSR_FFLAGS_REGNUM
+               || regnum == RISCV_CSR_FRM_REGNUM);
       else
        return regnum < RISCV_FIRST_FP_REGNUM;
     }
@@ -984,7 +1011,7 @@ public:
       LUI,
       SD,
       SW,
-      /* These are needed for software breakopint support.  */
+      /* These are needed for software breakpoint support.  */
       JAL,
       JALR,
       BEQ,
@@ -1359,10 +1386,12 @@ riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc)
        m_opcode = OTHER;
     }
   else
-    internal_error (__FILE__, __LINE__,
-                   _("unable to decode %d byte instructions in "
-                     "prologue at %s"), m_length,
-                   core_addr_to_string (pc));
+    {
+      /* This must be a 6 or 8 byte instruction, we don't currently decode
+        any of these, so just ignore it.  */
+      gdb_assert (m_length == 6 || m_length == 8);
+      m_opcode = OTHER;
+    }
 }
 
 /* The prologue scanner.  This is currently only used for skipping the
@@ -1593,62 +1622,59 @@ riscv_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp,
                       struct type *value_type, CORE_ADDR *real_pc,
                       CORE_ADDR *bp_addr, struct regcache *regcache)
 {
+  /* A nop instruction is 'add x0, x0, 0'.  */
+  static const gdb_byte nop_insn[] = { 0x13, 0x00, 0x00, 0x00 };
+
   /* Allocate space for a breakpoint, and keep the stack correctly
-     aligned.  */
+     aligned.  The space allocated here must be at least big enough to
+     accommodate the NOP_INSN defined above.  */
   sp -= 16;
   *bp_addr = sp;
   *real_pc = funaddr;
+
+  /* When we insert a breakpoint we select whether to use a compressed
+     breakpoint or not based on the existing contents of the memory.
+
+     If the breakpoint is being placed onto the stack as part of setting up
+     for an inferior call from GDB, then the existing stack contents may
+     randomly appear to be a compressed instruction, causing GDB to insert
+     a compressed breakpoint.  If this happens on a target that does not
+     support compressed instructions then this could cause problems.
+
+     To prevent this issue we write an uncompressed nop onto the stack at
+     the location where the breakpoint will be inserted.  In this way we
+     ensure that we always use an uncompressed breakpoint, which should
+     work on all targets.
+
+     We call TARGET_WRITE_MEMORY here so that if the write fails we don't
+     throw an exception.  Instead we ignore the error and move on.  The
+     assumption is that either GDB will error later when actually trying to
+     insert a software breakpoint, or GDB will use hardware breakpoints and
+     there will be no need to write to memory later.  */
+  int status = target_write_memory (*bp_addr, nop_insn, sizeof (nop_insn));
+
+  if (riscv_debug_breakpoints || riscv_debug_infcall)
+    fprintf_unfiltered (gdb_stdlog,
+                       "Writing %s-byte nop instruction to %s: %s\n",
+                       plongest (sizeof (nop_insn)),
+                       paddress (gdbarch, *bp_addr),
+                       (status == 0 ? "success" : "failed"));
+
   return sp;
 }
 
-/* Compute the alignment of the type T.  Used while setting up the
-   arguments for a dummy call.  */
+/* Implement the gdbarch type alignment method, overrides the generic
+   alignment algorithm for anything that is RISC-V specific.  */
 
-static int
-riscv_type_alignment (struct type *t)
+static ULONGEST
+riscv_type_align (gdbarch *gdbarch, type *type)
 {
-  t = check_typedef (t);
-  switch (TYPE_CODE (t))
-    {
-    default:
-      error (_("Could not compute alignment of type"));
-
-    case TYPE_CODE_RVALUE_REF:
-    case TYPE_CODE_PTR:
-    case TYPE_CODE_ENUM:
-    case TYPE_CODE_INT:
-    case TYPE_CODE_FLT:
-    case TYPE_CODE_REF:
-    case TYPE_CODE_CHAR:
-    case TYPE_CODE_BOOL:
-      return TYPE_LENGTH (t);
+  type = check_typedef (type);
+  if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type))
+    return std::min (TYPE_LENGTH (type), (ULONGEST) BIGGEST_ALIGNMENT);
 
-    case TYPE_CODE_ARRAY:
-      if (TYPE_VECTOR (t))
-       return std::min (TYPE_LENGTH (t), (unsigned) BIGGEST_ALIGNMENT);
-      /* FALLTHROUGH */
-
-    case TYPE_CODE_COMPLEX:
-      return riscv_type_alignment (TYPE_TARGET_TYPE (t));
-
-    case TYPE_CODE_STRUCT:
-    case TYPE_CODE_UNION:
-      {
-       int i;
-       int align = 1;
-
-       for (i = 0; i < TYPE_NFIELDS (t); ++i)
-         {
-           if (TYPE_FIELD_LOC_KIND (t, i) == FIELD_LOC_KIND_BITPOS)
-             {
-               int a = riscv_type_alignment (TYPE_FIELD_TYPE (t, i));
-               if (a > align)
-                 align = a;
-             }
-         }
-       return align;
-      }
-    }
+  /* Anything else will be aligned by the generic code.  */
+  return 0;
 }
 
 /* Holds information about a single argument either being passed to an
@@ -1783,8 +1809,8 @@ struct riscv_call_info
     : int_regs (RISCV_A0_REGNUM, RISCV_A0_REGNUM + 7),
       float_regs (RISCV_FA0_REGNUM, RISCV_FA0_REGNUM + 7)
   {
-    xlen = riscv_isa_xlen (gdbarch);
-    flen = riscv_isa_flen (gdbarch);
+    xlen = riscv_abi_xlen (gdbarch);
+    flen = riscv_abi_flen (gdbarch);
 
     /* Disable use of floating point registers if needed.  */
     if (!riscv_has_fp_abi (gdbarch))
@@ -1804,7 +1830,7 @@ struct riscv_call_info
   struct riscv_arg_reg float_regs;
 
   /* The XLEN and FLEN are copied in to this structure for convenience, and
-     are just the results of calling RISCV_ISA_XLEN and RISCV_ISA_FLEN.  */
+     are just the results of calling RISCV_ABI_XLEN and RISCV_ABI_FLEN.  */
   int xlen;
   int flen;
 };
@@ -1974,7 +2000,7 @@ riscv_call_arg_complex_float (struct riscv_arg_info *ainfo,
       int len = ainfo->length / 2;
 
       result = riscv_assign_reg_location (&ainfo->argloc[0],
-                                         &cinfo->float_regs, len, len);
+                                         &cinfo->float_regs, len, 0);
       gdb_assert (result);
 
       result = riscv_assign_reg_location (&ainfo->argloc[1],
@@ -1995,14 +2021,18 @@ class riscv_struct_info
 public:
   riscv_struct_info ()
     : m_number_of_fields (0),
-      m_types { nullptr, nullptr }
+      m_types { nullptr, nullptr },
+      m_offsets { 0, 0 }
   {
     /* Nothing.  */
   }
 
   /* Analyse TYPE descending into nested structures, count the number of
      scalar fields and record the types of the first two fields found.  */
-  void analyse (struct type *type);
+  void analyse (struct type *type)
+  {
+    analyse_inner (type, 0);
+  }
 
   /* The number of scalar fields found in the analysed type.  This is
      currently only accurate if the value returned is 0, 1, or 2 as the
@@ -2022,6 +2052,16 @@ public:
     return m_types[index];
   }
 
+  /* Return the offset of scalar field INDEX within the analysed type. Will
+     return 0 if there is no field at that index.  Only INDEX values 0 and
+     1 can be requested as the RiscV ABI only has special cases for
+     structures with 1 or 2 fields.  */
+  int field_offset (int index) const
+  {
+    gdb_assert (index < (sizeof (m_offsets) / sizeof (m_offsets[0])));
+    return m_offsets[index];
+  }
+
 private:
   /* The number of scalar fields found within the structure after recursing
      into nested structures.  */
@@ -2030,13 +2070,20 @@ private:
   /* The types of the first two scalar fields found within the structure
      after recursing into nested structures.  */
   struct type *m_types[2];
+
+  /* The offsets of the first two scalar fields found within the structure
+     after recursing into nested structures.  */
+  int m_offsets[2];
+
+  /* Recursive core for ANALYSE, the OFFSET parameter tracks the byte
+     offset from the start of the top level structure being analysed.  */
+  void analyse_inner (struct type *type, int offset);
 };
 
-/* Analyse TYPE descending into nested structures, count the number of
-   scalar fields and record the types of the first two fields found.  */
+/* See description in class declaration.  */
 
 void
-riscv_struct_info::analyse (struct type *type)
+riscv_struct_info::analyse_inner (struct type *type, int offset)
 {
   unsigned int count = TYPE_NFIELDS (type);
   unsigned int i;
@@ -2048,11 +2095,13 @@ riscv_struct_info::analyse (struct type *type)
 
       struct type *field_type = TYPE_FIELD_TYPE (type, i);
       field_type = check_typedef (field_type);
+      int field_offset
+       = offset + TYPE_FIELD_BITPOS (type, i) / TARGET_CHAR_BIT;
 
       switch (TYPE_CODE (field_type))
        {
        case TYPE_CODE_STRUCT:
-         analyse (field_type);
+         analyse_inner (field_type, field_offset);
          break;
 
        default:
@@ -2062,7 +2111,10 @@ riscv_struct_info::analyse (struct type *type)
             structure we can special case, and pass the structure in
             memory.  */
          if (m_number_of_fields < 2)
-           m_types[m_number_of_fields] = field_type;
+           {
+             m_types[m_number_of_fields] = field_type;
+             m_offsets[m_number_of_fields] = field_offset;
+           }
          m_number_of_fields++;
          break;
        }
@@ -2095,17 +2147,54 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo,
       if (sinfo.number_of_fields () == 1
          && TYPE_CODE (sinfo.field_type (0)) == TYPE_CODE_COMPLEX)
        {
-         gdb_assert (TYPE_LENGTH (ainfo->type)
-                     == TYPE_LENGTH (sinfo.field_type (0)));
-         return riscv_call_arg_complex_float (ainfo, cinfo);
+         /* The following is similar to RISCV_CALL_ARG_COMPLEX_FLOAT,
+            except we use the type of the complex field instead of the
+            type from AINFO, and the first location might be at a non-zero
+            offset.  */
+         if (TYPE_LENGTH (sinfo.field_type (0)) <= (2 * cinfo->flen)
+             && riscv_arg_regs_available (&cinfo->float_regs) >= 2
+             && !ainfo->is_unnamed)
+           {
+             bool result;
+             int len = TYPE_LENGTH (sinfo.field_type (0)) / 2;
+             int offset = sinfo.field_offset (0);
+
+             result = riscv_assign_reg_location (&ainfo->argloc[0],
+                                                 &cinfo->float_regs, len,
+                                                 offset);
+             gdb_assert (result);
+
+             result = riscv_assign_reg_location (&ainfo->argloc[1],
+                                                 &cinfo->float_regs, len,
+                                                 (offset + len));
+             gdb_assert (result);
+           }
+         else
+           riscv_call_arg_scalar_int (ainfo, cinfo);
+         return;
        }
 
       if (sinfo.number_of_fields () == 1
          && TYPE_CODE (sinfo.field_type (0)) == TYPE_CODE_FLT)
        {
-         gdb_assert (TYPE_LENGTH (ainfo->type)
-                     == TYPE_LENGTH (sinfo.field_type (0)));
-         return riscv_call_arg_scalar_float (ainfo, cinfo);
+         /* The following is similar to RISCV_CALL_ARG_SCALAR_FLOAT,
+            except we use the type of the first scalar field instead of
+            the type from AINFO.  Also the location might be at a non-zero
+            offset.  */
+         if (TYPE_LENGTH (sinfo.field_type (0)) > cinfo->flen
+             || ainfo->is_unnamed)
+           riscv_call_arg_scalar_int (ainfo, cinfo);
+         else
+           {
+             int offset = sinfo.field_offset (0);
+             int len = TYPE_LENGTH (sinfo.field_type (0));
+
+             if (!riscv_assign_reg_location (&ainfo->argloc[0],
+                                             &cinfo->float_regs,
+                                             len, offset))
+               riscv_call_arg_scalar_int (ainfo, cinfo);
+           }
+         return;
        }
 
       if (sinfo.number_of_fields () == 2
@@ -2115,17 +2204,14 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo,
          && TYPE_LENGTH (sinfo.field_type (1)) <= cinfo->flen
          && riscv_arg_regs_available (&cinfo->float_regs) >= 2)
        {
-         int len0, len1, offset;
-
-         gdb_assert (TYPE_LENGTH (ainfo->type) <= (2 * cinfo->flen));
-
-         len0 = TYPE_LENGTH (sinfo.field_type (0));
+         int len0 = TYPE_LENGTH (sinfo.field_type (0));
+         int offset = sinfo.field_offset (0);
          if (!riscv_assign_reg_location (&ainfo->argloc[0],
-                                         &cinfo->float_regs, len0, 0))
+                                         &cinfo->float_regs, len0, offset))
            error (_("failed during argument setup"));
 
-         len1 = TYPE_LENGTH (sinfo.field_type (1));
-         offset = align_up (len0, riscv_type_alignment (sinfo.field_type (1)));
+         int len1 = TYPE_LENGTH (sinfo.field_type (1));
+         offset = sinfo.field_offset (1);
          gdb_assert (len1 <= (TYPE_LENGTH (ainfo->type)
                               - TYPE_LENGTH (sinfo.field_type (0))));
 
@@ -2143,18 +2229,14 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo,
              && is_integral_type (sinfo.field_type (1))
              && TYPE_LENGTH (sinfo.field_type (1)) <= cinfo->xlen))
        {
-         int len0, len1, offset;
-
-         gdb_assert (TYPE_LENGTH (ainfo->type)
-                     <= (cinfo->flen + cinfo->xlen));
-
-         len0 = TYPE_LENGTH (sinfo.field_type (0));
+         int  len0 = TYPE_LENGTH (sinfo.field_type (0));
+         int offset = sinfo.field_offset (0);
          if (!riscv_assign_reg_location (&ainfo->argloc[0],
-                                         &cinfo->float_regs, len0, 0))
+                                         &cinfo->float_regs, len0, offset))
            error (_("failed during argument setup"));
 
-         len1 = TYPE_LENGTH (sinfo.field_type (1));
-         offset = align_up (len0, riscv_type_alignment (sinfo.field_type (1)));
+         int len1 = TYPE_LENGTH (sinfo.field_type (1));
+         offset = sinfo.field_offset (1);
          gdb_assert (len1 <= cinfo->xlen);
          if (!riscv_assign_reg_location (&ainfo->argloc[1],
                                          &cinfo->int_regs, len1, offset))
@@ -2169,22 +2251,18 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo,
              && TYPE_CODE (sinfo.field_type (1)) == TYPE_CODE_FLT
              && TYPE_LENGTH (sinfo.field_type (1)) <= cinfo->flen))
        {
-         int len0, len1, offset;
-
-         gdb_assert (TYPE_LENGTH (ainfo->type)
-                     <= (cinfo->flen + cinfo->xlen));
-
-         len0 = TYPE_LENGTH (sinfo.field_type (0));
-         len1 = TYPE_LENGTH (sinfo.field_type (1));
-         offset = align_up (len0, riscv_type_alignment (sinfo.field_type (1)));
+         int len0 = TYPE_LENGTH (sinfo.field_type (0));
+         int len1 = TYPE_LENGTH (sinfo.field_type (1));
 
          gdb_assert (len0 <= cinfo->xlen);
          gdb_assert (len1 <= cinfo->flen);
 
+         int offset = sinfo.field_offset (0);
          if (!riscv_assign_reg_location (&ainfo->argloc[0],
-                                         &cinfo->int_regs, len0, 0))
+                                         &cinfo->int_regs, len0, offset))
            error (_("failed during argument setup"));
 
+         offset = sinfo.field_offset (1);
          if (!riscv_assign_reg_location (&ainfo->argloc[1],
                                          &cinfo->float_regs,
                                          len1, offset))
@@ -2196,7 +2274,6 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo,
 
   /* Non of the structure flattening cases apply, so we just pass using
      the integer ABI.  */
-  ainfo->length = align_up (ainfo->length, cinfo->xlen);
   riscv_call_arg_scalar_int (ainfo, cinfo);
 }
 
@@ -2218,9 +2295,11 @@ riscv_arg_location (struct gdbarch *gdbarch,
 {
   ainfo->type = type;
   ainfo->length = TYPE_LENGTH (ainfo->type);
-  ainfo->align = riscv_type_alignment (ainfo->type);
+  ainfo->align = type_align (ainfo->type);
   ainfo->is_unnamed = is_unnamed;
   ainfo->contents = nullptr;
+  ainfo->argloc[0].c_length = 0;
+  ainfo->argloc[1].c_length = 0;
 
   switch (TYPE_CODE (ainfo->type))
     {
@@ -2242,7 +2321,7 @@ riscv_arg_location (struct gdbarch *gdbarch,
        }
 
       /* Recalculate the alignment requirement.  */
-      ainfo->align = riscv_type_alignment (ainfo->type);
+      ainfo->align = type_align (ainfo->type);
       riscv_call_arg_scalar_int (ainfo, cinfo);
       break;
 
@@ -2462,10 +2541,11 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
              memset (tmp, -1, sizeof (tmp));
            else
              memset (tmp, 0, sizeof (tmp));
-           memcpy (tmp, info->contents, info->argloc[0].c_length);
+           memcpy (tmp, (info->contents + info->argloc[0].c_offset),
+                   info->argloc[0].c_length);
            regcache->cooked_write (info->argloc[0].loc_data.regno, tmp);
            second_arg_length =
-             ((info->argloc[0].c_length < info->length)
+             (((info->argloc[0].c_length + info->argloc[0].c_offset) < info->length)
               ? info->argloc[1].c_length : 0);
            second_arg_data = info->contents + info->argloc[1].c_offset;
          }
@@ -2576,7 +2656,35 @@ riscv_return_value (struct gdbarch  *gdbarch,
 
   if (readbuf != nullptr || writebuf != nullptr)
     {
-        int regnum;
+       unsigned int arg_len;
+       struct value *abi_val;
+       gdb_byte *old_readbuf = nullptr;
+       int regnum;
+
+       /* We only do one thing at a time.  */
+       gdb_assert (readbuf == nullptr || writebuf == nullptr);
+
+       /* In some cases the argument is not returned as the declared type,
+          and we need to cast to or from the ABI type in order to
+          correctly access the argument.  When writing to the machine we
+          do the cast here, when reading from the machine the cast occurs
+          later, after extracting the value.  As the ABI type can be
+          larger than the declared type, then the read or write buffers
+          passed in might be too small.  Here we ensure that we are using
+          buffers of sufficient size.  */
+       if (writebuf != nullptr)
+         {
+           struct value *arg_val = value_from_contents (arg_type, writebuf);
+           abi_val = value_cast (info.type, arg_val);
+           writebuf = value_contents_raw (abi_val);
+         }
+       else
+         {
+           abi_val = allocate_value (info.type);
+           old_readbuf = readbuf;
+           readbuf = value_contents_raw (abi_val);
+         }
+       arg_len = TYPE_LENGTH (info.type);
 
        switch (info.argloc[0].loc_type)
          {
@@ -2584,32 +2692,54 @@ riscv_return_value (struct gdbarch  *gdbarch,
          case riscv_arg_info::location::in_reg:
            {
              regnum = info.argloc[0].loc_data.regno;
+              gdb_assert (info.argloc[0].c_length <= arg_len);
+              gdb_assert (info.argloc[0].c_length
+                         <= register_size (gdbarch, regnum));
 
              if (readbuf)
-               regcache->cooked_read (regnum, readbuf);
+               {
+                 gdb_byte *ptr = readbuf + info.argloc[0].c_offset;
+                 regcache->cooked_read_part (regnum, 0,
+                                             info.argloc[0].c_length,
+                                             ptr);
+               }
 
              if (writebuf)
-               regcache->cooked_write (regnum, writebuf);
+               {
+                 const gdb_byte *ptr = writebuf + info.argloc[0].c_offset;
+                 regcache->cooked_write_part (regnum, 0,
+                                              info.argloc[0].c_length,
+                                              ptr);
+               }
 
              /* A return value in register can have a second part in a
                 second register.  */
-             if (info.argloc[0].c_length < info.length)
+             if (info.argloc[1].c_length > 0)
                {
                  switch (info.argloc[1].loc_type)
                    {
                    case riscv_arg_info::location::in_reg:
                      regnum = info.argloc[1].loc_data.regno;
 
+                      gdb_assert ((info.argloc[0].c_length
+                                  + info.argloc[1].c_length) <= arg_len);
+                      gdb_assert (info.argloc[1].c_length
+                                 <= register_size (gdbarch, regnum));
+
                      if (readbuf)
                        {
                          readbuf += info.argloc[1].c_offset;
-                         regcache->cooked_read (regnum, readbuf);
+                         regcache->cooked_read_part (regnum, 0,
+                                                     info.argloc[1].c_length,
+                                                     readbuf);
                        }
 
                      if (writebuf)
                        {
                          writebuf += info.argloc[1].c_offset;
-                         regcache->cooked_write (regnum, writebuf);
+                         regcache->cooked_write_part (regnum, 0,
+                                                      info.argloc[1].c_length,
+                                                      writebuf);
                        }
                      break;
 
@@ -2642,6 +2772,16 @@ riscv_return_value (struct gdbarch  *gdbarch,
            error (_("invalid argument location"));
            break;
          }
+
+       /* This completes the cast from abi type back to the declared type
+          in the case that we are reading from the machine.  See the
+          comment at the head of this block for more details.  */
+       if (readbuf != nullptr)
+         {
+           struct value *arg_val = value_cast (arg_type, abi_val);
+           memcpy (old_readbuf, value_contents_raw (arg_val),
+                   TYPE_LENGTH (arg_type));
+         }
     }
 
   switch (info.argloc[0].loc_type)
@@ -2664,31 +2804,6 @@ riscv_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
   return align_down (addr, 16);
 }
 
-/* Implement the unwind_pc gdbarch method.  */
-
-static CORE_ADDR
-riscv_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
-{
-  return frame_unwind_register_unsigned (next_frame, RISCV_PC_REGNUM);
-}
-
-/* Implement the unwind_sp gdbarch method.  */
-
-static CORE_ADDR
-riscv_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
-{
-  return frame_unwind_register_unsigned (next_frame, RISCV_SP_REGNUM);
-}
-
-/* Implement the dummy_id gdbarch method.  */
-
-static struct frame_id
-riscv_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
-{
-  return frame_id_build (get_frame_register_signed (this_frame, RISCV_SP_REGNUM),
-                        get_frame_pc (this_frame));
-}
-
 /* Generate, or return the cached frame cache for the RiscV frame
    unwinder.  */
 
@@ -2760,17 +2875,16 @@ riscv_frame_this_id (struct frame_info *this_frame,
 {
   struct riscv_unwind_cache *cache;
 
-  TRY
+  try
     {
       cache = riscv_frame_cache (this_frame, prologue_cache);
       *this_id = cache->this_id;
     }
-  CATCH (ex, RETURN_MASK_ERROR)
+  catch (const gdb_exception_error &ex)
     {
       /* Ignore errors, this leaves the frame id as the predefined outer
          frame id which terminates the backtrace at this point.  */
     }
-  END_CATCH
 }
 
 /* Implement the prev_register callback for RiscV frame unwinder.  */
@@ -2833,27 +2947,9 @@ riscv_features_from_gdbarch_info (const struct gdbarch_info info)
                        _("unknown ELF header class %d"), eclass);
 
       if (e_flags & EF_RISCV_FLOAT_ABI_DOUBLE)
-       {
-         features.flen = 8;
-         features.hw_float_abi = true;
-       }
+       features.flen = 8;
       else if (e_flags & EF_RISCV_FLOAT_ABI_SINGLE)
-       {
-         features.flen = 4;
-         features.hw_float_abi = true;
-       }
-    }
-  else
-    {
-      const struct bfd_arch_info *binfo = info.bfd_arch_info;
-
-      if (binfo->bits_per_word == 32)
-       features.xlen = 4;
-      else if (binfo->bits_per_word == 64)
-       features.xlen = 8;
-      else
-       internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"),
-                       binfo->bits_per_word);
+       features.flen = 4;
     }
 
   return features;
@@ -2946,6 +3042,72 @@ riscv_setup_register_aliases (struct gdbarch *gdbarch,
     }
 }
 
+/* Implement the "dwarf2_reg_to_regnum" gdbarch method.  */
+
+static int
+riscv_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
+{
+  if (reg < RISCV_DWARF_REGNUM_X31)
+    return RISCV_ZERO_REGNUM + (reg - RISCV_DWARF_REGNUM_X0);
+
+  else if (reg < RISCV_DWARF_REGNUM_F31)
+    return RISCV_FIRST_FP_REGNUM + (reg - RISCV_DWARF_REGNUM_F0);
+
+  return -1;
+}
+
+/* Implement the gcc_target_options method.  We have to select the arch and abi
+   from the feature info.  We have enough feature info to select the abi, but
+   not enough info for the arch given all of the possible architecture
+   extensions.  So choose reasonable defaults for now.  */
+
+static std::string
+riscv_gcc_target_options (struct gdbarch *gdbarch)
+{
+  int isa_xlen = riscv_isa_xlen (gdbarch);
+  int isa_flen = riscv_isa_flen (gdbarch);
+  int abi_xlen = riscv_abi_xlen (gdbarch);
+  int abi_flen = riscv_abi_flen (gdbarch);
+  std::string target_options;
+
+  target_options = "-march=rv";
+  if (isa_xlen == 8)
+    target_options += "64";
+  else
+    target_options += "32";
+  if (isa_flen == 8)
+    target_options += "gc";
+  else if (isa_flen == 4)
+    target_options += "imafc";
+  else
+    target_options += "imac";
+
+  target_options += " -mabi=";
+  if (abi_xlen == 8)
+    target_options += "lp64";
+  else
+    target_options += "ilp32";
+  if (abi_flen == 8)
+    target_options += "d";
+  else if (abi_flen == 4)
+    target_options += "f";
+
+  /* The gdb loader doesn't handle link-time relaxation relocations.  */
+  target_options += " -mno-relax";
+
+  return target_options;
+}
+
+/* Implement the gnu_triplet_regexp method.  A single compiler supports both
+   32-bit and 64-bit code, and may be named riscv32 or riscv64 or (not
+   recommended) riscv.  */
+
+static const char *
+riscv_gnu_triplet_regexp (struct gdbarch *gdbarch)
+{
+  return "riscv(32|64)?";
+}
+
 /* Initialize the current architecture based on INFO.  If possible,
    re-use an architecture from ARCHES, which is a list of
    architectures already created during this debugging session.
@@ -3008,7 +3170,21 @@ riscv_gdbarch_init (struct gdbarch_info info,
       valid_p &= riscv_check_tdesc_feature (tdesc_data, feature_fpu,
                                             &riscv_freg_feature);
 
-      int bitsize = tdesc_register_bitsize (feature_fpu, "ft0");
+      /* Search for the first floating point register (by any alias), to
+         determine the bitsize.  */
+      int bitsize = -1;
+      const auto &fp0 = riscv_freg_feature.registers[0];
+
+      for (const char *name : fp0.names)
+       {
+         if (tdesc_unnumbered_register (feature_fpu, name))
+           {
+             bitsize = tdesc_register_bitsize (feature_fpu, name);
+             break;
+           }
+       }
+
+      gdb_assert (bitsize != -1);
       features.flen = (bitsize / 8);
 
       if (riscv_debug_gdbarch)
@@ -3045,25 +3221,26 @@ riscv_gdbarch_init (struct gdbarch_info info,
   /* Have a look at what the supplied (if any) bfd object requires of the
      target, then check that this matches with what the target is
      providing.  */
-  struct riscv_gdbarch_features info_features
+  struct riscv_gdbarch_features abi_features
     = riscv_features_from_gdbarch_info (info);
-  if (info_features.xlen != 0 && info_features.xlen != features.xlen)
+  /* In theory a binary compiled for RV32 could run on an RV64 target,
+     however, this has not been tested in GDB yet, so for now we require
+     that the requested xlen match the targets xlen.  */
+  if (abi_features.xlen != 0 && abi_features.xlen != features.xlen)
     error (_("bfd requires xlen %d, but target has xlen %d"),
-           info_features.xlen, features.xlen);
-  if (info_features.flen != 0 && info_features.flen != features.flen)
+            abi_features.xlen, features.xlen);
+  /* We do support running binaries compiled for 32-bit float on targets
+     with 64-bit float, so we only complain if the binary requires more
+     than the target has available.  */
+  if (abi_features.flen > features.flen)
     error (_("bfd requires flen %d, but target has flen %d"),
-           info_features.flen, features.flen);
-
-  /* If the xlen from INFO_FEATURES is 0 then this indicates either there
-     is no bfd object, or nothing useful could be extracted from it, in
-     this case we enable hardware float abi if the target has floating
-     point registers.
+            abi_features.flen, features.flen);
 
-     If the xlen from INFO_FEATURES is not 0, and the flen in
-     INFO_FEATURES is also not 0, then this indicates that the supplied
-     bfd does require hardware floating point abi.  */
-  if (info_features.xlen == 0 || info_features.flen != 0)
-    features.hw_float_abi = (features.flen > 0);
+  /* If the ABI_FEATURES xlen is 0 then this indicates we got no useful abi
+     features from the INFO object.  In this case we assume that the xlen
+     abi matches the hardware.  */
+  if (abi_features.xlen == 0)
+    abi_features.xlen = features.xlen;
 
   /* Find a candidate among the list of pre-declared architectures.  */
   for (arches = gdbarch_list_lookup_by_info (arches, &info);
@@ -3075,7 +3252,8 @@ riscv_gdbarch_init (struct gdbarch_info info,
          gdbarch.  */
       struct gdbarch_tdep *other_tdep = gdbarch_tdep (arches->gdbarch);
 
-      if (other_tdep->features != features)
+      if (other_tdep->isa_features != features
+         || other_tdep->abi_features != abi_features)
         continue;
 
       break;
@@ -3090,7 +3268,8 @@ riscv_gdbarch_init (struct gdbarch_info info,
   /* None found, so create a new architecture from the information provided.  */
   tdep = new (struct gdbarch_tdep);
   gdbarch = gdbarch_alloc (&info, tdep);
-  tdep->features = features;
+  tdep->isa_features = features;
+  tdep->abi_features = abi_features;
 
   /* Target data types.  */
   set_gdbarch_short_bit (gdbarch, 16);
@@ -3103,6 +3282,7 @@ riscv_gdbarch_init (struct gdbarch_info info,
   set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
   set_gdbarch_ptr_bit (gdbarch, riscv_isa_xlen (gdbarch) * 8);
   set_gdbarch_char_signed (gdbarch, 0);
+  set_gdbarch_type_align (gdbarch, riscv_type_align);
 
   /* Information about the target architecture.  */
   set_gdbarch_return_value (gdbarch, riscv_return_value);
@@ -3115,15 +3295,10 @@ riscv_gdbarch_init (struct gdbarch_info info,
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
   set_gdbarch_frame_align (gdbarch, riscv_frame_align);
 
-  /* Functions to access frame data.  */
-  set_gdbarch_unwind_pc (gdbarch, riscv_unwind_pc);
-  set_gdbarch_unwind_sp (gdbarch, riscv_unwind_sp);
-
   /* Functions handling dummy frames.  */
   set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
   set_gdbarch_push_dummy_code (gdbarch, riscv_push_dummy_code);
   set_gdbarch_push_dummy_call (gdbarch, riscv_push_dummy_call);
-  set_gdbarch_dummy_id (gdbarch, riscv_dummy_id);
 
   /* Frame unwinders.  Use DWARF debug info if available, otherwise use our own
      unwinder.  */
@@ -3133,6 +3308,9 @@ riscv_gdbarch_init (struct gdbarch_info info,
   /* Register architecture.  */
   riscv_add_reggroups (gdbarch);
 
+  /* Internal <-> external register number maps.  */
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, riscv_dwarf_reg_to_regnum);
+
   /* We reserve all possible register numbers for the known registers.
      This means the target description mechanism will add any target
      specific registers after this number.  This helps make debugging GDB
@@ -3174,9 +3352,15 @@ riscv_gdbarch_init (struct gdbarch_info info,
     riscv_setup_register_aliases (gdbarch, &riscv_freg_feature);
   riscv_setup_register_aliases (gdbarch, &riscv_csr_feature);
 
+  /* Compile command hooks.  */
+  set_gdbarch_gcc_target_options (gdbarch, riscv_gcc_target_options);
+  set_gdbarch_gnu_triplet_regexp (gdbarch, riscv_gnu_triplet_regexp);
+
   /* Hook in OS ABI-specific overrides, if they have been registered.  */
   gdbarch_init_osabi (info, gdbarch);
 
+  register_riscv_ravenscar_ops (gdbarch);
+
   return gdbarch;
 }
 
This page took 0.035509 seconds and 4 git commands to generate.