AArch64: gdbserver: read pauth registers
[deliverable/binutils-gdb.git] / gdb / riscv-tdep.c
index 88b79af866f752404e8cad774a84a61cb873ca86..8a996f32d39846c29cc406333556d45c4254d1e6 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-2019 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -50,7 +50,7 @@
 #include "dwarf2-frame.h"
 #include "user-regs.h"
 #include "valprint.h"
-#include "common-defs.h"
+#include "common/common-defs.h"
 #include "opcode/riscv-opc.h"
 #include "cli/cli-decode.h"
 #include "observable.h"
@@ -185,7 +185,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 +361,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 +377,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 +401,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.  */
@@ -896,7 +912,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;
     }
@@ -1542,10 +1561,16 @@ riscv_scan_prologue (struct gdbarch *gdbarch,
          if (stack.find_reg (gdbarch, i, &offset))
             {
               if (riscv_debug_unwinder)
-                fprintf_unfiltered (gdb_stdlog,
-                                    "Register $%s at stack offset %ld\n",
-                                    gdbarch_register_name (gdbarch, i),
-                                    offset);
+               {
+                 /* Display OFFSET as a signed value, the offsets are from
+                    the frame base address to the registers location on
+                    the stack, with a descending stack this means the
+                    offsets are always negative.  */
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "Register $%s at stack offset %s\n",
+                                     gdbarch_register_name (gdbarch, i),
+                                     plongest ((LONGEST) offset));
+               }
               trad_frame_set_addr (cache->regs, i, offset);
             }
        }
@@ -1607,6 +1632,7 @@ riscv_type_alignment (struct type *t)
     default:
       error (_("Could not compute alignment of type"));
 
+    case TYPE_CODE_RANGE:
     case TYPE_CODE_RVALUE_REF:
     case TYPE_CODE_PTR:
     case TYPE_CODE_ENUM:
@@ -1777,8 +1803,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))
@@ -1798,7 +1824,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;
 };
@@ -2139,9 +2165,6 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo,
        {
          int len0, len1, offset;
 
-         gdb_assert (TYPE_LENGTH (ainfo->type)
-                     <= (cinfo->flen + cinfo->xlen));
-
          len0 = TYPE_LENGTH (sinfo.field_type (0));
          if (!riscv_assign_reg_location (&ainfo->argloc[0],
                                          &cinfo->float_regs, len0, 0))
@@ -2165,9 +2188,6 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo,
        {
          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)));
@@ -2190,7 +2210,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);
 }
 
@@ -2570,7 +2589,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)
          {
@@ -2578,12 +2625,19 @@ 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);
+               regcache->cooked_read_part (regnum, 0,
+                                           info.argloc[0].c_length,
+                                           readbuf);
 
              if (writebuf)
-               regcache->cooked_write (regnum, writebuf);
+               regcache->cooked_write_part (regnum, 0,
+                                            info.argloc[0].c_length,
+                                            writebuf);
 
              /* A return value in register can have a second part in a
                 second register.  */
@@ -2594,16 +2648,25 @@ riscv_return_value (struct gdbarch  *gdbarch,
                    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;
 
@@ -2636,6 +2699,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)
@@ -2658,31 +2731,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.  */
 
@@ -2827,15 +2875,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;
-       }
+       features.flen = 4;
     }
   else
     {
@@ -2940,6 +2982,20 @@ 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;
+}
+
 /* 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.
@@ -3039,25 +3095,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);
+            abi_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.
-
-     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);
@@ -3069,7 +3126,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;
@@ -3084,7 +3142,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);
@@ -3109,15 +3168,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.  */
@@ -3127,6 +3181,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
This page took 0.028706 seconds and 4 git commands to generate.