Avoid "Invalid parameter passed to C runtime function" warning
[deliverable/binutils-gdb.git] / gdb / riscv-tdep.c
index 48ca2accb4abf61d8fe372bf63945bc84bb7db31..408ab0af24b73a3ca9c1470b722be371b08b6bcf 100644 (file)
@@ -59,6 +59,9 @@
 /* The stack must be 16-byte aligned.  */
 #define SP_ALIGNMENT 16
 
+/* The biggest alignment that the target supports.  */
+#define BIGGEST_ALIGNMENT 16
+
 /* Forward declarations.  */
 static bool riscv_has_feature (struct gdbarch *gdbarch, char feature);
 
@@ -290,34 +293,44 @@ static unsigned int riscv_debug_infcall = 0;
 
 static unsigned int riscv_debug_unwinder = 0;
 
-/* Read the MISA register from the target.  The register will only be read
-   once, and the value read will be cached.  If the register can't be read
-   from the target then a default value (0) will be returned.  If the
-   pointer READ_P is not null, then the bool pointed to is updated  to
-   indicate if the value returned was read from the target (true) or is the
-   default (false).  */
+/* Read the MISA register from the target.  There are a couple of locations
+   that the register might be found, these are all tried.  If the MISA
+   register can't be found at all then the default value of 0 is returned,
+   this is inline with the RISC-V specification.  */
 
 static uint32_t
-riscv_read_misa_reg (bool *read_p)
+riscv_read_misa_reg ()
 {
   uint32_t value = 0;
 
   if (target_has_registers)
     {
+      /* Old cores might have MISA located at a different offset.  */
+      static int misa_regs[] =
+       { RISCV_CSR_MISA_REGNUM, RISCV_CSR_LEGACY_MISA_REGNUM };
+
       struct frame_info *frame = get_current_frame ();
 
-      TRY
+      for (int i = 0; i < ARRAY_SIZE (misa_regs); ++i)
        {
-         value = get_frame_register_unsigned (frame,
-                                              RISCV_CSR_MISA_REGNUM);
-       }
-      CATCH (ex, RETURN_MASK_ERROR)
-       {
-         /* Old cores might have MISA located at a different offset.  */
-         value = get_frame_register_unsigned (frame,
-                                              RISCV_CSR_LEGACY_MISA_REGNUM);
+         bool success = false;
+
+         TRY
+           {
+             value = get_frame_register_unsigned (frame, misa_regs[i]);
+             success = true;
+           }
+         CATCH (ex, RETURN_MASK_ERROR)
+           {
+             /* Ignore errors, it is acceptable for a target to not
+                provide a MISA register, in which case the default value
+                of 0 should be used.  */
+           }
+         END_CATCH
+
+         if (success)
+           break;
        }
-      END_CATCH
     }
 
   return value;
@@ -330,21 +343,16 @@ riscv_read_misa_reg (bool *read_p)
 static bool
 riscv_has_feature (struct gdbarch *gdbarch, char feature)
 {
-  bool have_read_misa = false;
-  uint32_t misa;
-
   gdb_assert (feature >= 'A' && feature <= 'Z');
 
-  misa = riscv_read_misa_reg (&have_read_misa);
-  if (!have_read_misa || misa == 0)
+  uint32_t misa = riscv_read_misa_reg ();
+  if (misa == 0)
     misa = gdbarch_tdep (gdbarch)->core_features;
 
   return (misa & (1 << (feature - 'A'))) != 0;
 }
 
-/* Return the width in bytes  of the general purpose registers for GDBARCH.
-   Possible return values are 4, 8, or 16 for RiscV variants RV32, RV64, or
-   RV128.  */
+/* See riscv-tdep.h.  */
 
 int
 riscv_isa_xlen (struct gdbarch *gdbarch)
@@ -363,12 +371,9 @@ riscv_isa_xlen (struct gdbarch *gdbarch)
     }
 }
 
-/* Return the width in bytes of the floating point registers for GDBARCH.
-   If this architecture has no floating point registers, then return 0.
-   Possible values are 4, 8, or 16 for depending on which of single, double
-   or quad floating point support is available.  */
+/* See riscv-tdep.h.  */
 
-static int
+int
 riscv_isa_flen (struct gdbarch *gdbarch)
 {
   if (riscv_has_feature (gdbarch, 'Q'))
@@ -413,18 +418,34 @@ riscv_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
 {
   if (use_compressed_breakpoints == AUTO_BOOLEAN_AUTO)
     {
+      bool unaligned_p = false;
       gdb_byte buf[1];
 
-      /* Read the opcode byte to determine the instruction length.  */
-      read_code (*pcptr, buf, 1);
+      /* Some targets don't support unaligned reads.  The address can only
+        be unaligned if the C extension is supported.  So it is safe to
+        use a compressed breakpoint in this case.  */
+      if (*pcptr & 0x2)
+       unaligned_p = true;
+      else
+       {
+         /* Read the opcode byte to determine the instruction length.  */
+         read_code (*pcptr, buf, 1);
+       }
 
       if (riscv_debug_breakpoints)
-       fprintf_unfiltered
-         (gdb_stdlog,
-          "Using %s for breakpoint at %s (instruction length %d)\n",
-          riscv_insn_length (buf[0]) == 2 ? "C.EBREAK" : "EBREAK",
-          paddress (gdbarch, *pcptr), riscv_insn_length (buf[0]));
-      if (riscv_insn_length (buf[0]) == 2)
+       {
+         const char *bp = (unaligned_p || riscv_insn_length (buf[0]) == 2
+                           ? "C.EBREAK" : "EBREAK");
+
+         fprintf_unfiltered (gdb_stdlog, "Using %s for breakpoint at %s ",
+                             bp, paddress (gdbarch, *pcptr));
+         if (unaligned_p)
+           fprintf_unfiltered (gdb_stdlog, "(unaligned address)\n");
+         else
+           fprintf_unfiltered (gdb_stdlog, "(instruction length %d)\n",
+                               riscv_insn_length (buf[0]));
+       }
+      if (unaligned_p || riscv_insn_length (buf[0]) == 2)
        return 2;
       else
        return 4;
@@ -482,11 +503,22 @@ riscv_register_name (struct gdbarch *gdbarch, int regnum)
 
   if (regnum >= RISCV_FIRST_CSR_REGNUM && regnum <= RISCV_LAST_CSR_REGNUM)
     {
-      static char buf[20];
+#define DECLARE_CSR(NAME,VALUE) \
+      case RISCV_ ## VALUE ## _REGNUM: return # NAME;
 
-      xsnprintf (buf, sizeof (buf), "csr%d",
-                regnum - RISCV_FIRST_CSR_REGNUM);
-      return buf;
+      switch (regnum)
+       {
+         #include "opcode/riscv-opc.h"
+       default:
+          {
+            static char buf[20];
+
+            xsnprintf (buf, sizeof (buf), "csr%d",
+                       regnum - RISCV_FIRST_CSR_REGNUM);
+            return buf;
+          }
+       }
+#undef DECLARE_CSR
     }
 
   if (regnum == RISCV_PRIV_REGNUM)
@@ -1227,7 +1259,9 @@ riscv_insn::fetch_instruction (struct gdbarch *gdbarch,
   return extract_unsigned_integer (buf, instlen, byte_order);
 }
 
-/* Fetch from target memory an instruction at PC and decode it.  */
+/* Fetch from target memory an instruction at PC and decode it.  This can
+   throw an error if the memory access fails, callers are responsible for
+   handling this error if that is appropriate.  */
 
 void
 riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc)
@@ -1611,6 +1645,10 @@ riscv_type_alignment (struct type *t)
       return TYPE_LENGTH (t);
 
     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));
 
@@ -1701,6 +1739,9 @@ struct riscv_arg_info
        then this offset will be set to 0.  */
     int c_offset;
   } argloc[2];
+
+  /* TRUE if this is an unnamed argument.  */
+  bool is_unnamed;
 };
 
 /* Information about a set of registers being used for passing arguments as
@@ -1894,12 +1935,19 @@ riscv_call_arg_scalar_int (struct riscv_arg_info *ainfo,
     }
   else
     {
-      int len = (ainfo->length > cinfo->xlen) ? cinfo->xlen : ainfo->length;
+      int len = std::min (ainfo->length, cinfo->xlen);
+      int align = std::max (ainfo->align, cinfo->xlen);
+
+      /* Unnamed arguments in registers that require 2*XLEN alignment are
+        passed in an aligned register pair.  */
+      if (ainfo->is_unnamed && (align == cinfo->xlen * 2)
+         && cinfo->int_regs.next_regnum & 1)
+       cinfo->int_regs.next_regnum++;
 
       if (!riscv_assign_reg_location (&ainfo->argloc[0],
                                      &cinfo->int_regs, len, 0))
        riscv_assign_stack_location (&ainfo->argloc[0],
-                                    &cinfo->memory, len, ainfo->align);
+                                    &cinfo->memory, len, align);
 
       if (len < ainfo->length)
        {
@@ -2176,7 +2224,9 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo,
    selected from CINFO which holds information about what call argument
    locations are available for use next.  The TYPE is the type of the
    argument being passed, this information is recorded into AINFO (along
-   with some additional information derived from the type).
+   with some additional information derived from the type).  IS_UNNAMED
+   is true if this is an unnamed (stdarg) argument, this info is also
+   recorded into AINFO.
 
    After assigning a location to AINFO, CINFO will have been updated.  */
 
@@ -2184,11 +2234,12 @@ static void
 riscv_arg_location (struct gdbarch *gdbarch,
                    struct riscv_arg_info *ainfo,
                    struct riscv_call_info *cinfo,
-                   struct type *type)
+                   struct type *type, bool is_unnamed)
 {
   ainfo->type = type;
   ainfo->length = TYPE_LENGTH (ainfo->type);
   ainfo->align = riscv_type_alignment (ainfo->type);
+  ainfo->is_unnamed = is_unnamed;
   ainfo->contents = nullptr;
 
   switch (TYPE_CODE (ainfo->type))
@@ -2323,7 +2374,7 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
                       int nargs,
                       struct value **args,
                       CORE_ADDR sp,
-                      int struct_return,
+                      function_call_return_method return_method,
                       CORE_ADDR struct_addr)
 {
   int i;
@@ -2337,8 +2388,13 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
 
   CORE_ADDR osp = sp;
 
+  struct type *ftype = check_typedef (value_type (function));
+
+  if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
+    ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
+
   /* We'll use register $a0 if we're returning a struct.  */
-  if (struct_return)
+  if (return_method == return_method_struct)
     ++call_info.int_regs.next_regnum;
 
   for (i = 0; i < nargs; ++i)
@@ -2350,7 +2406,8 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
       arg_value = args[i];
       arg_type = check_typedef (value_type (arg_value));
 
-      riscv_arg_location (gdbarch, info, &call_info, arg_type);
+      riscv_arg_location (gdbarch, info, &call_info, arg_type,
+                         TYPE_VARARGS (ftype) && i >= TYPE_NFIELDS (ftype));
 
       if (info->type != arg_type)
        arg_value = value_cast (info->type, arg_value);
@@ -2368,7 +2425,7 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
               (riscv_has_fp_abi (gdbarch) ? "is" : "is not"));
       fprintf_unfiltered (gdb_stdlog, ": xlen: %d\n: flen: %d\n",
               call_info.xlen, call_info.flen);
-      if (struct_return)
+      if (return_method == return_method_struct)
        fprintf_unfiltered (gdb_stdlog,
                            "[*] struct return pointer in register $A0\n");
       for (i = 0; i < nargs; ++i)
@@ -2395,7 +2452,7 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
 
   /* Now load the argument into registers, or onto the stack.  */
 
-  if (struct_return)
+  if (return_method == return_method_struct)
     {
       gdb_byte buf[sizeof (LONGEST)];
 
@@ -2527,7 +2584,7 @@ riscv_return_value (struct gdbarch  *gdbarch,
   struct type *arg_type;
 
   arg_type = check_typedef (type);
-  riscv_arg_location (gdbarch, &info, &call_info, arg_type);
+  riscv_arg_location (gdbarch, &info, &call_info, arg_type, false);
 
   if (riscv_debug_infcall > 0)
     {
@@ -2723,8 +2780,17 @@ riscv_frame_this_id (struct frame_info *this_frame,
 {
   struct riscv_unwind_cache *cache;
 
-  cache = riscv_frame_cache (this_frame, prologue_cache);
-  *this_id = cache->this_id;
+  TRY
+    {
+      cache = riscv_frame_cache (this_frame, prologue_cache);
+      *this_id = cache->this_id;
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      /* 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.  */
This page took 0.027943 seconds and 4 git commands to generate.