]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/riscv-tdep.c
Automatic Copyright Year update after running gdb/copyright.py
[thirdparty/binutils-gdb.git] / gdb / riscv-tdep.c
index 8b55bc33dedd956928937b3af4f11471ba81ace6..5a6269887e7de44540b7b1344774e34b46e3603a 100644 (file)
@@ -1,6 +1,6 @@
 /* Target-dependent code for the RISC-V architecture, for GDB.
 
-   Copyright (C) 2018-2021 Free Software Foundation, Inc.
+   Copyright (C) 2018-2022 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -101,6 +101,9 @@ static const char *riscv_feature_name_fpu = "org.gnu.gdb.riscv.fpu";
 static const char *riscv_feature_name_virtual = "org.gnu.gdb.riscv.virtual";
 static const char *riscv_feature_name_vector = "org.gnu.gdb.riscv.vector";
 
+/* The current set of options to be passed to the disassembler.  */
+static char *riscv_disassembler_options;
+
 /* Cached information about a frame.  */
 
 struct riscv_unwind_cache
@@ -566,8 +569,8 @@ private:
     for (auto &reg : m_registers)
       {
        int csr_num = reg.regnum - RISCV_FIRST_CSR_REGNUM;
-       const char *alias = xstrprintf ("csr%d", csr_num);
-       reg.names.push_back (alias);
+       gdb::unique_xmalloc_ptr<char> alias = xstrprintf ("csr%d", csr_num);
+       reg.names.push_back (alias.release ());
       }
   }
 };
@@ -730,7 +733,8 @@ show_riscv_debug_variable (struct ui_file *file, int from_tty,
 int
 riscv_isa_xlen (struct gdbarch *gdbarch)
 {
-  return gdbarch_tdep (gdbarch)->isa_features.xlen;
+  riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+  return tdep->isa_features.xlen;
 }
 
 /* See riscv-tdep.h.  */
@@ -738,7 +742,8 @@ riscv_isa_xlen (struct gdbarch *gdbarch)
 int
 riscv_abi_xlen (struct gdbarch *gdbarch)
 {
-  return gdbarch_tdep (gdbarch)->abi_features.xlen;
+  riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+  return tdep->abi_features.xlen;
 }
 
 /* See riscv-tdep.h.  */
@@ -746,7 +751,8 @@ riscv_abi_xlen (struct gdbarch *gdbarch)
 int
 riscv_isa_flen (struct gdbarch *gdbarch)
 {
-  return gdbarch_tdep (gdbarch)->isa_features.flen;
+  riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+  return tdep->isa_features.flen;
 }
 
 /* See riscv-tdep.h.  */
@@ -754,7 +760,8 @@ riscv_isa_flen (struct gdbarch *gdbarch)
 int
 riscv_abi_flen (struct gdbarch *gdbarch)
 {
-  return gdbarch_tdep (gdbarch)->abi_features.flen;
+  riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+  return tdep->abi_features.flen;
 }
 
 /* See riscv-tdep.h.  */
@@ -762,7 +769,8 @@ riscv_abi_flen (struct gdbarch *gdbarch)
 bool
 riscv_abi_embedded (struct gdbarch *gdbarch)
 {
-  return gdbarch_tdep (gdbarch)->abi_features.embedded;
+  riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+  return tdep->abi_features.embedded;
 }
 
 /* Return true if the target for GDBARCH has floating point hardware.  */
@@ -778,7 +786,8 @@ riscv_has_fp_regs (struct gdbarch *gdbarch)
 static bool
 riscv_has_fp_abi (struct gdbarch *gdbarch)
 {
-  return gdbarch_tdep (gdbarch)->abi_features.flen > 0;
+  riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+  return tdep->abi_features.flen > 0;
 }
 
 /* Return true if REGNO is a floating pointer register.  */
@@ -858,7 +867,7 @@ riscv_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
     case 4:
       return ebreak;
     default:
-      gdb_assert_not_reached (_("unhandled breakpoint kind"));
+      gdb_assert_not_reached ("unhandled breakpoint kind");
     }
 }
 
@@ -901,7 +910,7 @@ riscv_register_name (struct gdbarch *gdbarch, int regnum)
      will show up in 'info register all'.  Unless, we identify the
      duplicate copies of these registers (in riscv_tdesc_unknown_reg) and
      then hide the registers here by giving them no name.  */
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
   if (tdep->duplicate_fflags_regnum == regnum)
     return NULL;
   if (tdep->duplicate_frm_regnum == regnum)
@@ -929,7 +938,7 @@ riscv_register_name (struct gdbarch *gdbarch, int regnum)
 static struct type *
 riscv_fpreg_d_type (struct gdbarch *gdbarch)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
 
   if (tdep->riscv_fpreg_d_type == nullptr)
     {
@@ -1059,7 +1068,7 @@ riscv_print_one_register_info (struct gdbarch *gdbarch,
          && regtype->field (2).type ()->code () == TYPE_CODE_FLT))
     {
       struct value_print_options opts;
-      const gdb_byte *valaddr = value_contents_for_printing (val);
+      const gdb_byte *valaddr = value_contents_for_printing (val).data ();
       enum bfd_endian byte_order = type_byte_order (regtype);
 
       get_user_print_options (&opts);
@@ -1251,7 +1260,7 @@ riscv_is_regnum_a_named_csr (int regnum)
 static bool
 riscv_is_unknown_csr (struct gdbarch *gdbarch, int regnum)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
   return (regnum >= tdep->unknown_csrs_first_regnum
          && regnum < (tdep->unknown_csrs_first_regnum
                       + tdep->unknown_csrs_count));
@@ -1411,6 +1420,7 @@ public:
       SW,
       LD,
       LW,
+      MV,
       /* These are needed for software breakpoint support.  */
       JAL,
       JALR,
@@ -1789,9 +1799,11 @@ riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc)
       else if (xlen != 4 && is_c_sdsp_insn (ival))
        decode_css_type_insn (SD, ival, EXTRACT_CSSTYPE_SDSP_IMM (ival));
       /* C_JR and C_MV have the same opcode.  If RS2 is 0, then this is a C_JR.
-        So must try to match C_JR first as it ahs more bits in mask.  */
+        So must try to match C_JR first as it has more bits in mask.  */
       else if (is_c_jr_insn (ival))
        decode_cr_type_insn (JALR, ival);
+      else if (is_c_mv_insn (ival))
+       decode_cr_type_insn (MV, ival);
       else if (is_c_j_insn (ival))
        decode_cj_type_insn (JAL, ival);
       else if (is_c_beqz_insn (ival))
@@ -1944,7 +1956,7 @@ riscv_scan_prologue (struct gdbarch *gdbarch,
        }
       else if (insn.opcode () == riscv_insn::ADD)
        {
-         /* Handle: addi REG1, REG2, IMM  */
+         /* Handle: add REG1, REG2, REG3  */
          gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
          gdb_assert (insn.rs1 () < RISCV_NUM_INTEGER_REGS);
          gdb_assert (insn.rs2 () < RISCV_NUM_INTEGER_REGS);
@@ -1964,6 +1976,14 @@ riscv_scan_prologue (struct gdbarch *gdbarch,
                                            insn.imm_signed ()),
                           (insn.opcode () == riscv_insn::LW ? 4 : 8));
        }
+      else if (insn.opcode () == riscv_insn::MV)
+       {
+         /* Handle: c.mv RD, RS2  */
+         gdb_assert (insn.rd () < RISCV_NUM_INTEGER_REGS);
+         gdb_assert (insn.rs2 () < RISCV_NUM_INTEGER_REGS);
+         gdb_assert (insn.rs2 () > 0);
+         regs[insn.rd ()] = regs[insn.rs2 ()];
+       }
       else
        {
          end_prologue_addr = cur_pc;
@@ -2531,13 +2551,13 @@ riscv_struct_info::analyse_inner (struct type *type, int offset)
 
   for (i = 0; i < count; ++i)
     {
-      if (TYPE_FIELD_LOC_KIND (type, i) != FIELD_LOC_KIND_BITPOS)
+      if (type->field (i).loc_kind () != FIELD_LOC_KIND_BITPOS)
        continue;
 
       struct type *field_type = type->field (i).type ();
       field_type = check_typedef (field_type);
       int field_offset
-       = offset + TYPE_FIELD_BITPOS (type, i) / TARGET_CHAR_BIT;
+       = offset + type->field (i).loc_bitpos () / TARGET_CHAR_BIT;
 
       switch (field_type->code ())
        {
@@ -2750,6 +2770,7 @@ riscv_arg_location (struct gdbarch *gdbarch,
     case TYPE_CODE_RANGE:
     case TYPE_CODE_ENUM:
     case TYPE_CODE_PTR:
+    case TYPE_CODE_FIXED_POINT:
       if (ainfo->length <= cinfo->xlen)
        {
          ainfo->type = builtin_type (gdbarch)->builtin_long;
@@ -2860,7 +2881,7 @@ riscv_print_arg_location (ui_file *stream, struct gdbarch *gdbarch,
       break;
 
     default:
-      gdb_assert_not_reached (_("unknown argument location type"));
+      gdb_assert_not_reached ("unknown argument location type");
     }
 }
 
@@ -2931,7 +2952,7 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
 
       if (info->type != arg_type)
        arg_value = value_cast (info->type, arg_value);
-      info->contents = value_contents (arg_value);
+      info->contents = value_contents (arg_value).data ();
     }
 
   /* Adjust the stack pointer and align it.  */
@@ -3022,7 +3043,7 @@ riscv_push_dummy_call (struct gdbarch *gdbarch,
          break;
 
        default:
-         gdb_assert_not_reached (_("unknown argument location type"));
+         gdb_assert_not_reached ("unknown argument location type");
        }
 
       if (second_arg_length > 0)
@@ -3124,15 +3145,37 @@ riscv_return_value (struct gdbarch  *gdbarch,
           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);
+           struct value *arg_val;
+
+           if (is_fixed_point_type (arg_type))
+             {
+               /* Convert the argument to the type used to pass
+                  the return value, but being careful to preserve
+                  the fact that the value needs to be returned
+                  unscaled.  */
+               gdb_mpz unscaled;
+
+               unscaled.read (gdb::make_array_view (writebuf,
+                                                    TYPE_LENGTH (arg_type)),
+                              type_byte_order (arg_type),
+                              arg_type->is_unsigned ());
+               abi_val = allocate_value (info.type);
+               unscaled.write (value_contents_raw (abi_val),
+                               type_byte_order (info.type),
+                               info.type->is_unsigned ());
+             }
+           else
+             {
+               arg_val = value_from_contents (arg_type, writebuf);
+               abi_val = value_cast (info.type, arg_val);
+             }
+           writebuf = value_contents_raw (abi_val).data ();
          }
        else
          {
            abi_val = allocate_value (info.type);
            old_readbuf = readbuf;
-           readbuf = value_contents_raw (abi_val);
+           readbuf = value_contents_raw (abi_val).data ();
          }
        arg_len = TYPE_LENGTH (info.type);
 
@@ -3229,8 +3272,26 @@ riscv_return_value (struct gdbarch  *gdbarch,
           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),
+           struct value *arg_val;
+
+           if (is_fixed_point_type (arg_type))
+             {
+               /* Convert abi_val to the actual return type, but
+                  being careful to preserve the fact that abi_val
+                  is unscaled.  */
+               gdb_mpz unscaled;
+
+               unscaled.read (value_contents (abi_val),
+                              type_byte_order (info.type),
+                              info.type->is_unsigned ());
+               arg_val = allocate_value (arg_type);
+               unscaled.write (value_contents_raw (arg_val),
+                               type_byte_order (arg_type),
+                               arg_type->is_unsigned ());
+             }
+           else
+             arg_val = value_cast (arg_type, abi_val);
+           memcpy (old_readbuf, value_contents_raw (arg_val).data (),
                    TYPE_LENGTH (arg_type));
          }
     }
@@ -3549,7 +3610,7 @@ riscv_tdesc_unknown_reg (struct gdbarch *gdbarch, tdesc_feature *feature,
      record their register numbers here.  */
   if (strcmp (tdesc_feature_name (feature), riscv_freg_feature.name ()) == 0)
     {
-      struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+      riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
       int *regnum_ptr = nullptr;
 
       if (strcmp (reg_name, "fflags") == 0)
@@ -3580,7 +3641,7 @@ riscv_tdesc_unknown_reg (struct gdbarch *gdbarch, tdesc_feature *feature,
      about register groups in riscv_register_reggroup_p.  */
   if (strcmp (tdesc_feature_name (feature), riscv_csr_feature.name ()) == 0)
     {
-      struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+      riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
       if (tdep->unknown_csrs_first_regnum == -1)
        tdep->unknown_csrs_first_regnum = possible_regnum;
       gdb_assert (tdep->unknown_csrs_first_regnum
@@ -3617,7 +3678,6 @@ riscv_gdbarch_init (struct gdbarch_info info,
                    struct gdbarch_list *arches)
 {
   struct gdbarch *gdbarch;
-  struct gdbarch_tdep *tdep;
   struct riscv_gdbarch_features features;
   const struct target_desc *tdesc = info.target_desc;
 
@@ -3682,7 +3742,8 @@ riscv_gdbarch_init (struct gdbarch_info info,
       /* Check that the feature set of the ARCHES matches the feature set
         we are looking for.  If it doesn't then we can't reuse this
         gdbarch.  */
-      struct gdbarch_tdep *other_tdep = gdbarch_tdep (arches->gdbarch);
+      riscv_gdbarch_tdep *other_tdep
+       = (riscv_gdbarch_tdep *) gdbarch_tdep (arches->gdbarch);
 
       if (other_tdep->isa_features != features
          || other_tdep->abi_features != abi_features)
@@ -3695,7 +3756,7 @@ riscv_gdbarch_init (struct gdbarch_info info,
     return arches->gdbarch;
 
   /* None found, so create a new architecture from the information provided.  */
-  tdep = new (struct gdbarch_tdep);
+  riscv_gdbarch_tdep *tdep = new riscv_gdbarch_tdep;
   gdbarch = gdbarch_alloc (&info, tdep);
   tdep->isa_features = features;
   tdep->abi_features = abi_features;
@@ -3786,6 +3847,11 @@ riscv_gdbarch_init (struct gdbarch_info info,
   set_gdbarch_gcc_target_options (gdbarch, riscv_gcc_target_options);
   set_gdbarch_gnu_triplet_regexp (gdbarch, riscv_gnu_triplet_regexp);
 
+  /* Disassembler options support.  */
+  set_gdbarch_valid_disassembler_options (gdbarch,
+                                         disassembler_options_riscv ());
+  set_gdbarch_disassembler_options (gdbarch, &riscv_disassembler_options);
+
   /* Hook in OS ABI-specific overrides, if they have been registered.  */
   gdbarch_init_osabi (info, gdbarch);
 
@@ -3801,7 +3867,8 @@ static CORE_ADDR
 riscv_next_pc (struct regcache *regcache, CORE_ADDR pc)
 {
   struct gdbarch *gdbarch = regcache->arch ();
-  const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  const riscv_gdbarch_tdep *tdep
+    = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
   struct riscv_insn insn;
   CORE_ADDR next_pc;
 
@@ -4007,15 +4074,11 @@ _initialize_riscv_tdep ()
 
   /* Add root prefix command for all "set debug riscv" and "show debug
      riscv" commands.  */
-  add_basic_prefix_cmd ("riscv", no_class,
-                       _("RISC-V specific debug commands."),
-                       &setdebugriscvcmdlist, 0,
-                       &setdebuglist);
-
-  add_show_prefix_cmd ("riscv", no_class,
-                      _("RISC-V specific debug commands."),
-                      &showdebugriscvcmdlist, 0,
-                      &showdebuglist);
+  add_setshow_prefix_cmd ("riscv", no_class,
+                         _("RISC-V specific debug commands."),
+                         _("RISC-V specific debug commands."),
+                         &setdebugriscvcmdlist, &showdebugriscvcmdlist,
+                         &setdebuglist, &showdebuglist);
 
   add_setshow_zuinteger_cmd ("breakpoints", class_maintenance,
                             &riscv_debug_breakpoints,  _("\
@@ -4058,13 +4121,11 @@ initialisation process."),
                             &setdebugriscvcmdlist, &showdebugriscvcmdlist);
 
   /* Add root prefix command for all "set riscv" and "show riscv" commands.  */
-  add_basic_prefix_cmd ("riscv", no_class,
-                       _("RISC-V specific commands."),
-                       &setriscvcmdlist, 0, &setlist);
-
-  add_show_prefix_cmd ("riscv", no_class,
-                      _("RISC-V specific commands."),
-                      &showriscvcmdlist, 0, &showlist);
+  add_setshow_prefix_cmd ("riscv", no_class,
+                         _("RISC-V specific commands."),
+                         _("RISC-V specific commands."),
+                         &setriscvcmdlist, &showriscvcmdlist,
+                         &setlist, &showlist);
 
 
   use_compressed_breakpoints = AUTO_BOOLEAN_AUTO;