This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 1/2] RISC-V GDB Port


---
 gdb/Makefile.in                 |    5 +
 gdb/config/riscv/linux.mh       |   30 +
 gdb/features/Makefile           |    2 +
 gdb/features/riscv.c            |   86 +++
 gdb/features/riscv.xml          |   81 +++
 gdb/gdbserver/linux-riscv-low.c |  221 +++++++
 gdb/regformats/riscv.dat        |   69 ++
 gdb/riscv-linux-nat.c           |   77 +++
 gdb/riscv-linux-tdep.c          |   80 +++
 gdb/riscv-linux-tdep.h          |   30 +
 gdb/riscv-tdep.c                | 1368 +++++++++++++++++++++++++++++++++++++++
 gdb/riscv-tdep.h                |   96 +++
 include/gdb/sim-riscv.h         |   98 +++
 13 files changed, 2243 insertions(+)
 create mode 100644 gdb/config/riscv/linux.mh
 create mode 100644 gdb/features/riscv.c
 create mode 100644 gdb/features/riscv.xml
 create mode 100644 gdb/gdbserver/linux-riscv-low.c
 create mode 100644 gdb/regformats/riscv.dat
 create mode 100644 gdb/riscv-linux-nat.c
 create mode 100644 gdb/riscv-linux-tdep.c
 create mode 100644 gdb/riscv-linux-tdep.h
 create mode 100644 gdb/riscv-tdep.c
 create mode 100644 gdb/riscv-tdep.h
 create mode 100644 include/gdb/sim-riscv.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 268c2c6..e92c13c 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -853,6 +853,8 @@ ALL_TARGET_OBS = \
 	ppc-sysv-tdep.o \
 	ppc64-tdep.o \
 	ravenscar-thread.o \
+	riscv-tdep.o \
+	riscv-linux-tdep.o \
 	rl78-tdep.o \
 	rs6000-aix-tdep.o \
 	rs6000-lynx178-tdep.o \
@@ -1406,6 +1408,7 @@ HFILES_NO_SRCDIR = \
 	remote.h \
 	remote-fileio.h \
 	remote-notif.h \
+	riscv-tdep.h \
 	rs6000-aix-tdep.h \
 	rs6000-tdep.h \
 	s390-linux-tdep.h \
@@ -2595,6 +2598,8 @@ ALLDEPFILES = \
 	procfs.c \
 	ravenscar-thread.c \
 	remote-sim.c \
+	riscv-tdep.c \
+	riscv-linux-tdep.c \
 	rl78-tdep.c \
 	rs6000-lynx178-tdep.c \
 	rs6000-nat.c \
diff --git a/gdb/config/riscv/linux.mh b/gdb/config/riscv/linux.mh
new file mode 100644
index 0000000..4ec9f47
--- /dev/null
+++ b/gdb/config/riscv/linux.mh
@@ -0,0 +1,30 @@
+#  Host: RISC-V based machine running GNU/Linux
+#
+#  Copyright (C) 2016 Free Software Foundation, Inc.
+#  Contributed by Albert Ou <albert@sifive.com>.
+#
+#  This file is part of GDB.
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 3 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+NAT_FILE= config/nm-linux.h
+NATDEPFILES= inf-ptrace.o fork-child.o riscv-linux-nat.o \
+	proc-service.o linux-thread-db.o linux-nat.o linux-fork.o \
+	linux-procfs.o linux-ptrace.o linux-osdata.o linux-waitpid.o \
+	linux-namespaces.o linux-personality.o
+NAT_CDEPS = $(srcdir)/proc-service.list
+
+# The dynamically loaded libthread_db needs access to symbols in the
+# gdb executable.
+LOADLIBES= -ldl $(RDYNAMIC)
diff --git a/gdb/features/Makefile b/gdb/features/Makefile
index 3bc8b5a..318fa53 100644
--- a/gdb/features/Makefile
+++ b/gdb/features/Makefile
@@ -66,6 +66,7 @@ WHICH = aarch64 \
 	microblaze-with-stack-protect \
 	mips64-linux mips64-dsp-linux \
 	nios2-linux \
+	riscv \
 	rs6000/powerpc-32 \
 	rs6000/powerpc-32l rs6000/powerpc-altivec32l rs6000/powerpc-e500l \
 	rs6000/powerpc-64l rs6000/powerpc-altivec64l rs6000/powerpc-vsx32l \
@@ -179,6 +180,7 @@ XMLTOC = \
 	nds32.xml \
 	nios2-linux.xml \
 	nios2.xml \
+	riscv.xml \
 	rs6000/powerpc-32.xml \
 	rs6000/powerpc-32l.xml \
 	rs6000/powerpc-403.xml \
diff --git a/gdb/features/riscv.c b/gdb/features/riscv.c
new file mode 100644
index 0000000..8422976
--- /dev/null
+++ b/gdb/features/riscv.c
@@ -0,0 +1,86 @@
+/* THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi:set ro:
+  Original: riscv.xml */
+
+#include "defs.h"
+#include "osabi.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_riscv;
+static void
+initialize_tdesc_riscv (void)
+{
+  struct target_desc *result = allocate_target_description ();
+  struct tdesc_feature *feature;
+
+  set_tdesc_architecture (result, bfd_scan_arch ("riscv:rv64"));
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.rv64i");
+  tdesc_create_reg (feature, "x0", 0, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x1", 1, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x2", 2, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x3", 3, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x4", 4, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x5", 5, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x6", 6, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x7", 7, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x8", 8, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x9", 9, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x10", 10, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x11", 11, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x12", 12, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x13", 13, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x14", 14, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x15", 15, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x16", 16, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x17", 17, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x18", 18, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x19", 19, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x20", 20, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x21", 21, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x22", 22, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x23", 23, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x24", 24, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x25", 25, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x26", 26, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x27", 27, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x28", 28, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x29", 29, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x30", 30, 1, "general", 64, "int");
+  tdesc_create_reg (feature, "x31", 31, 1, "general", 64, "int");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.rv64d");
+  tdesc_create_reg (feature, "f0", 32, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f1", 33, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f2", 34, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f3", 35, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f4", 36, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f5", 37, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f6", 38, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f7", 39, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f8", 40, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f9", 41, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f10", 42, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f11", 43, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f12", 44, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f13", 45, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f14", 46, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f15", 47, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f16", 48, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f17", 49, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f18", 50, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f19", 51, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f20", 52, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f21", 53, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f22", 54, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f23", 55, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f24", 56, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f25", 57, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f26", 58, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f27", 59, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f28", 60, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f29", 61, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f30", 62, 1, "float", 64, "float");
+  tdesc_create_reg (feature, "f31", 63, 1, "float", 64, "float");
+
+  tdesc_riscv = result;
+}
diff --git a/gdb/features/riscv.xml b/gdb/features/riscv.xml
new file mode 100644
index 0000000..94e630c
--- /dev/null
+++ b/gdb/features/riscv.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2015-2017 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>riscv:rv64</architecture>
+
+  <feature name="org.gnu.gdb.riscv.rv64i">
+    <reg name="x0"  bitsize="64" group="general"/>
+    <reg name="x1"  bitsize="64" group="general"/>
+    <reg name="x2"  bitsize="64" group="general"/>
+    <reg name="x3"  bitsize="64" group="general"/>
+    <reg name="x4"  bitsize="64" group="general"/>
+    <reg name="x5"  bitsize="64" group="general"/>
+    <reg name="x6"  bitsize="64" group="general"/>
+    <reg name="x7"  bitsize="64" group="general"/>
+    <reg name="x8"  bitsize="64" group="general"/>
+    <reg name="x9"  bitsize="64" group="general"/>
+    <reg name="x10" bitsize="64" group="general"/>
+    <reg name="x11" bitsize="64" group="general"/>
+    <reg name="x12" bitsize="64" group="general"/>
+    <reg name="x13" bitsize="64" group="general"/>
+    <reg name="x14" bitsize="64" group="general"/>
+    <reg name="x15" bitsize="64" group="general"/>
+    <reg name="x16" bitsize="64" group="general"/>
+    <reg name="x17" bitsize="64" group="general"/>
+    <reg name="x18" bitsize="64" group="general"/>
+    <reg name="x19" bitsize="64" group="general"/>
+    <reg name="x20" bitsize="64" group="general"/>
+    <reg name="x21" bitsize="64" group="general"/>
+    <reg name="x22" bitsize="64" group="general"/>
+    <reg name="x23" bitsize="64" group="general"/>
+    <reg name="x24" bitsize="64" group="general"/>
+    <reg name="x25" bitsize="64" group="general"/>
+    <reg name="x26" bitsize="64" group="general"/>
+    <reg name="x27" bitsize="64" group="general"/>
+    <reg name="x28" bitsize="64" group="general"/>
+    <reg name="x29" bitsize="64" group="general"/>
+    <reg name="x30" bitsize="64" group="general"/>
+    <reg name="x31" bitsize="64" group="general"/>
+  </feature>
+
+  <feature name="org.gnu.gdb.riscv.rv64d">
+    <reg name="f0"  bitsize="64" group="float" type="float"/>
+    <reg name="f1"  bitsize="64" group="float" type="float"/>
+    <reg name="f2"  bitsize="64" group="float" type="float"/>
+    <reg name="f3"  bitsize="64" group="float" type="float"/>
+    <reg name="f4"  bitsize="64" group="float" type="float"/>
+    <reg name="f5"  bitsize="64" group="float" type="float"/>
+    <reg name="f6"  bitsize="64" group="float" type="float"/>
+    <reg name="f7"  bitsize="64" group="float" type="float"/>
+    <reg name="f8"  bitsize="64" group="float" type="float"/>
+    <reg name="f9"  bitsize="64" group="float" type="float"/>
+    <reg name="f10" bitsize="64" group="float" type="float"/>
+    <reg name="f11" bitsize="64" group="float" type="float"/>
+    <reg name="f12" bitsize="64" group="float" type="float"/>
+    <reg name="f13" bitsize="64" group="float" type="float"/>
+    <reg name="f14" bitsize="64" group="float" type="float"/>
+    <reg name="f15" bitsize="64" group="float" type="float"/>
+    <reg name="f16" bitsize="64" group="float" type="float"/>
+    <reg name="f17" bitsize="64" group="float" type="float"/>
+    <reg name="f18" bitsize="64" group="float" type="float"/>
+    <reg name="f19" bitsize="64" group="float" type="float"/>
+    <reg name="f20" bitsize="64" group="float" type="float"/>
+    <reg name="f21" bitsize="64" group="float" type="float"/>
+    <reg name="f22" bitsize="64" group="float" type="float"/>
+    <reg name="f23" bitsize="64" group="float" type="float"/>
+    <reg name="f24" bitsize="64" group="float" type="float"/>
+    <reg name="f25" bitsize="64" group="float" type="float"/>
+    <reg name="f26" bitsize="64" group="float" type="float"/>
+    <reg name="f27" bitsize="64" group="float" type="float"/>
+    <reg name="f28" bitsize="64" group="float" type="float"/>
+    <reg name="f29" bitsize="64" group="float" type="float"/>
+    <reg name="f30" bitsize="64" group="float" type="float"/>
+    <reg name="f31" bitsize="64" group="float" type="float"/>
+  </feature>
+</target>
diff --git a/gdb/gdbserver/linux-riscv-low.c b/gdb/gdbserver/linux-riscv-low.c
new file mode 100644
index 0000000..444082c
--- /dev/null
+++ b/gdb/gdbserver/linux-riscv-low.c
@@ -0,0 +1,221 @@
+/* GNU/Linux/RISC-V specific low level interface, GDBserver.
+
+   Copyright (C) 2012-2017 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "server.h"
+#include "linux-low.h"
+
+#include <arch/abi.h>
+#include "nat/gdb_ptrace.h"
+
+/* Defined in auto-generated file reg-riscv.c.  */
+void init_registers_riscv (void);
+extern const struct target_desc *tdesc_riscv;
+
+#define riscv_num_regs 32
+
+static int riscv_regmap[] =
+{
+   0,  1,  2,  3,  4,  5,  6,  7,
+   8,  9, 10, 11, 12, 13, 14, 15,
+  16, 17, 18, 19, 20, 21, 22, 23,
+  24, 25, 26, 27, 28, 29, 30, 31,
+  32, 33, 34, 35, 36, 37, 38, 39,
+  40, 41, 42, 43, 44, 45, 46, 47,
+  48, 49, 50, 51, 52, 53, 54, 55,
+  56, 57, 58, 59, 60, 61, 62, 63
+};
+
+static int
+riscv_cannot_fetch_register (int regno)
+{
+  if (regno >= 0 && regno < 63)
+    return 0;
+  else
+    return 1;
+}
+
+static int
+riscv_cannot_store_register (int regno)
+{
+  if (regno >= 0 && regno < 63)
+    return 0;
+  else
+    return 1;
+}
+
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind".  */
+
+static const gdb_byte ebreak[] = { 0x73, 0x00, 0x10, 0x00, };
+static const gdb_byte c_ebreak[] = { 0x02, 0x90 };
+
+static const gdb_byte *
+riscv_sw_breakpoint_from_kind (int kind, int *size)
+{
+  *size = kind;
+  switch (kind)
+    {
+    case 2:
+      return c_ebreak;
+    case 4:
+      return ebreak;
+    default:
+      gdb_assert(0);
+    }
+}
+
+static int
+riscv_breakpoint_at (CORE_ADDR where)
+{
+  uint8_t insn[4];
+
+  (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
+  if (insn[0] == ebreak[0] && inst[1] == ebreak[1]
+      && inst[2] == ebreak[2] && inst[3] == ebreak[3])
+    return 1;
+  if (insn[0] == c_ebreak[0] && inst[1] == c_ebreak[1])
+    return 1;
+
+  /* If necessary, recognize more trap instructions here.  GDB only uses the
+     one.  */
+  return 0;
+}
+
+static void
+riscv_fill_gregset (struct regcache *regcache, void *buf)
+{
+  int i;
+
+  for (i = 0; i < riscv_num_regs; i++)
+    if (riscv_regmap[i] != -1)
+      collect_register (regcache, i, ((uint_reg_t *) buf) + riscv_regmap[i]);
+}
+
+static void
+riscv_store_gregset (struct regcache *regcache, const void *buf)
+{
+  int i;
+
+  for (i = 0; i < riscv_num_regs; i++)
+    if (riscv_regmap[i] != -1)
+      supply_register (regcache, i, ((uint_reg_t *) buf) + riscv_regmap[i]);
+}
+
+static struct regset_info riscv_regsets[] =
+{
+  { PTRACE_GETREGS, PTRACE_SETREGS, 0, riscv_num_regs * 8,
+    GENERAL_REGS, riscv_fill_gregset, riscv_store_gregset },
+  NULL_REGSET
+};
+
+static struct regsets_info riscv_regsets_info =
+  {
+    riscv_regsets, /* regsets */
+    0, /* num_regsets */
+    NULL, /* disabled_regsets */
+  };
+
+static struct usrregs_info riscv_usrregs_info =
+  {
+    riscv_num_regs,
+    riscv_regmap,
+  };
+
+static struct regs_info regs_info =
+  {
+    NULL, /* regset_bitmap */
+    &riscv_usrregs_info,
+    &riscv_regsets_info,
+  };
+
+static const struct regs_info *
+riscv_regs_info (void)
+{
+  return &regs_info;
+}
+
+static void
+riscv_arch_setup (void)
+{
+  int pid = pid_of (current_thread);
+  unsigned int machine;
+  int is_elf64 = linux_pid_exe_is_elf_64_file (pid, &machine);
+
+  if (sizeof (void *) == 4)
+    if (is_elf64 > 0)
+      error (_("Can't debug 64-bit process with 32-bit GDBserver"));
+
+  if (!is_elf64)
+    current_process ()->tdesc = tdesc_riscvgx32;
+  else
+    current_process ()->tdesc = tdesc_riscvgx;
+}
+
+/* Support for hardware single step.  */
+
+static int
+riscv_supports_hardware_single_step (void)
+{
+  return 0;
+}
+
+
+struct linux_target_ops the_low_target =
+{
+  riscv_arch_setup,
+  riscv_regs_info,
+  riscv_cannot_fetch_register,
+  riscv_cannot_store_register,
+  NULL,
+  linux_get_pc_64bit,
+  linux_set_pc_64bit,
+  NULL, /* breakpoint_kind_from_pc */
+  riscv_sw_breakpoint_from_kind,
+  NULL,
+  0,
+  riscv_breakpoint_at,
+  NULL, /* supports_z_point_type */
+  NULL, /* insert_point */
+  NULL, /* remove_point */
+  NULL, /* stopped_by_watchpoint */
+  NULL, /* stopped_data_address */
+  NULL, /* collect_ptrace_register */
+  NULL, /* supply_ptrace_register */
+  NULL, /* siginfo_fixup */
+  NULL, /* new_process */
+  NULL, /* new_thread */
+  NULL, /* new_fork */
+  NULL, /* prepare_to_resume */
+  NULL, /* process_qsupported */
+  NULL, /* supports_tracepoints */
+  NULL, /* get_thread_area */
+  NULL, /* install_fast_tracepoint_jump_pad */
+  NULL, /* emit_ops */
+  NULL, /* get_min_fast_tracepoint_insn_len */
+  NULL, /* supports_range_stepping */
+  NULL, /* breakpoint_kind_from_current_state */
+  riscv_supports_hardware_single_step,
+};
+
+void
+initialize_low_arch (void)
+{
+  init_registers_riscv();
+
+  initialize_regsets_info (&riscv_regsets_info);
+}
diff --git a/gdb/regformats/riscv.dat b/gdb/regformats/riscv.dat
new file mode 100644
index 0000000..01047fa
--- /dev/null
+++ b/gdb/regformats/riscv.dat
@@ -0,0 +1,69 @@
+# THIS FILE IS GENERATED.  -*- buffer-read-only: t -*- vi :set ro:
+# Generated from: riscv.xml
+name:riscv
+xmltarget:riscv.xml
+expedite:
+64:x0
+64:x1
+64:x2
+64:x3
+64:x4
+64:x5
+64:x6
+64:x7
+64:x8
+64:x9
+64:x10
+64:x11
+64:x12
+64:x13
+64:x14
+64:x15
+64:x16
+64:x17
+64:x18
+64:x19
+64:x20
+64:x21
+64:x22
+64:x23
+64:x24
+64:x25
+64:x26
+64:x27
+64:x28
+64:x29
+64:x30
+64:x31
+64:f0
+64:f1
+64:f2
+64:f3
+64:f4
+64:f5
+64:f6
+64:f7
+64:f8
+64:f9
+64:f10
+64:f11
+64:f12
+64:f13
+64:f14
+64:f15
+64:f16
+64:f17
+64:f18
+64:f19
+64:f20
+64:f21
+64:f22
+64:f23
+64:f24
+64:f25
+64:f26
+64:f27
+64:f28
+64:f29
+64:f30
+64:f31
diff --git a/gdb/riscv-linux-nat.c b/gdb/riscv-linux-nat.c
new file mode 100644
index 0000000..6accb7a
--- /dev/null
+++ b/gdb/riscv-linux-nat.c
@@ -0,0 +1,77 @@
+/* Native-dependent code for GNU/Linux RISC-V.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+   Contributed by Albert Ou <albert@sifive.com>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+
+#include "inferior.h"
+#include "regcache.h"
+
+#include <sys/ptrace.h>
+#include "gregset.h"
+
+#include "riscv-tdep.h"
+#include "riscv-linux-tdep.h"
+
+/* Transfering the general-purpose registers between GDB, inferiors
+   and core files.  */
+
+/* Fill GDB's register cache with the general-purpose register values
+   in *GREGSETP.  */
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
+{
+  regcache_supply_regset (&riscv_linux_gregset, regcache, -1,
+			  (const gdb_byte *) gregsetp,
+			  (RISCV_NGREG));
+}
+
+/* Fill register REGNUM (if it is a general-purpose register) in
+   *GREGSETP with the value in GDB's register cache.  If REGNUM is -1,
+   do this for all registers.  */
+
+void
+fill_gregset (const struct regcache *regcache,
+	      gdb_gregset_t *gregsetp, int regno)
+{
+  regcache_collect_regset (&riscv_linux_gregset, regcache,
+			   regno, (gdb_byte *) gregsetp,
+			   (RISCV_NGREG));
+}
+
+/* Transfering floating-point registers between GDB, inferiors and cores.  */
+
+/* Fill GDB's register cache with the floating-point and SSE register
+   values in *FPREGSETP.  */
+
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
+{
+}
+
+/* Fill register REGNUM (if it is a floating-point or SSE register) in
+   *FPREGSETP with the value in GDB's register cache.  If REGNUM is
+   -1, do this for all registers.  */
+
+void
+fill_fpregset (const struct regcache *regcache,
+	       gdb_fpregset_t *fpregsetp, int regnum)
+{
+}
diff --git a/gdb/riscv-linux-tdep.c b/gdb/riscv-linux-tdep.c
new file mode 100644
index 0000000..145a3cf
--- /dev/null
+++ b/gdb/riscv-linux-tdep.c
@@ -0,0 +1,80 @@
+/* Target-dependent code for GNU/Linux RISC-V.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+   Contributed by Albert Ou <albert@sifive.com>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+
+#include "gdbarch.h"
+#include "osabi.h"
+#include "linux-tdep.h"
+#include "solib-svr4.h"
+#include "glibc-tdep.h"
+
+#include "riscv-tdep.h"
+#include "riscv-linux-tdep.h"
+
+#include "regcache.h"
+#include "regset.h"
+
+static const struct regcache_map_entry riscv_linux_gregmap[] =
+{
+  { 1,  RISCV_PC_REGNUM, 0 },
+  { 31, RISCV_RA_REGNUM, 0 }, /* x1 to x31 */
+  { 0 }
+};
+
+const struct regset riscv_linux_gregset =
+{
+  riscv_linux_gregmap, regcache_supply_regset, regcache_collect_regset
+};
+
+static void
+riscv_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+					  iterate_over_regset_sections_cb *cb,
+					  void *cb_data,
+					  const struct regcache *regcache)
+{
+  cb (".reg", (RISCV_NGREG * riscv_isa_regsize (gdbarch)),
+      &riscv_linux_gregset, NULL, cb_data);
+}
+
+static void
+riscv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  linux_init_abi (info, gdbarch);
+
+  /* GNU/Linux uses SVR4-style shared libraries.  */
+  set_solib_svr4_fetch_link_map_offsets
+    (gdbarch, gdbarch_tdep (gdbarch)->riscv_abi == RISCV_ABI_FLAG_RV32I ?
+      svr4_ilp32_fetch_link_map_offsets :
+      svr4_lp64_fetch_link_map_offsets);
+
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, riscv_linux_iterate_over_regset_sections);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_riscv_linux_tdep;
+
+void
+_initialize_riscv_linux_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_LINUX,
+			  riscv_linux_init_abi);
+}
diff --git a/gdb/riscv-linux-tdep.h b/gdb/riscv-linux-tdep.h
new file mode 100644
index 0000000..d5758ca
--- /dev/null
+++ b/gdb/riscv-linux-tdep.h
@@ -0,0 +1,30 @@
+/* Target-dependent header for GNU/Linux RISC-V.
+
+   Copyright (C) 2015 Free Software Foundation, Inc.
+   Contributed by Albert Ou <albert@sifive.com>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef RISCV_LINUX_TDEP_H
+#define RISCV_LINUX_TDEP_H
+
+#include "regset.h"
+
+#define RISCV_NGREG (32)
+
+extern const struct regset riscv_linux_gregset;
+
+#endif
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
new file mode 100644
index 0000000..7522cfa
--- /dev/null
+++ b/gdb/riscv-tdep.c
@@ -0,0 +1,1368 @@
+/* Target-dependent code for the RISC-V architecture, for GDB.
+
+   Copyright (C) 1988-2015 Free Software Foundation, Inc.
+
+   Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
+   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
+   and by Todd Snyder <todd@bluespec.com>
+   and by Mike Frysinger <vapier@gentoo.org>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "inferior.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "language.h"
+#include "gdbcore.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "target.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "osabi.h"
+#include "riscv-tdep.h"
+#include "block.h"
+#include "reggroups.h"
+#include "opcode/riscv.h"
+#include "elf/riscv.h"
+#include "elf-bfd.h"
+#include "symcat.h"
+#include "sim-regno.h"
+#include "gdb/sim-riscv.h"
+#include "dis-asm.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "trad-frame.h"
+#include "infcall.h"
+#include "floatformat.h"
+#include "remote.h"
+#include "target-descriptions.h"
+#include "dwarf2-frame.h"
+#include "user-regs.h"
+#include "valprint.h"
+#include "common-defs.h"
+#include "opcode/riscv-opc.h"
+#include <algorithm>
+
+#define DECLARE_INSN(INSN_NAME, INSN_MATCH, INSN_MASK) \
+static inline bool is_ ## INSN_NAME ## _insn (long insn) \
+{ \
+  return (insn & INSN_MASK) == INSN_MATCH; \
+}
+#include "opcode/riscv-opc.h"
+#undef DECLARE_INSN
+
+struct riscv_frame_cache
+{
+  CORE_ADDR base;
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+static const char * const riscv_gdb_reg_names[RISCV_LAST_FP_REGNUM + 1] =
+{
+  "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
+  "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
+  "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
+  "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
+  "pc",
+  "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
+  "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
+  "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+  "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+};
+
+struct register_alias
+{
+  const char *name;
+  int regnum;
+};
+
+static const struct register_alias riscv_register_aliases[] =
+{
+  { "zero", 0 },
+  { "ra", 1 },
+  { "sp", 2 },
+  { "gp", 3 },
+  { "tp", 4 },
+  { "t0", 5 },
+  { "t1", 6 },
+  { "t2", 7 },
+  { "fp", 8 },
+  { "s0", 8 },
+  { "s1", 9 },
+  { "a0", 10 },
+  { "a1", 11 },
+  { "a2", 12 },
+  { "a3", 13 },
+  { "a4", 14 },
+  { "a5", 15 },
+  { "a6", 16 },
+  { "a7", 17 },
+  { "s2", 18 },
+  { "s3", 19 },
+  { "s4", 20 },
+  { "s5", 21 },
+  { "s6", 22 },
+  { "s7", 23 },
+  { "s8", 24 },
+  { "s9", 25 },
+  { "s10", 26 },
+  { "s11", 27 },
+  { "t3", 28 },
+  { "t4", 29 },
+  { "t5", 30 },
+  { "t6", 31 },
+  /* pc is 32.  */
+  { "ft0", 33 },
+  { "ft1", 34 },
+  { "ft2", 35 },
+  { "ft3", 36 },
+  { "ft4", 37 },
+  { "ft5", 38 },
+  { "ft6", 39 },
+  { "ft7", 40 },
+  { "fs0", 41 },
+  { "fs1", 42 },
+  { "fa0", 43 },
+  { "fa1", 44 },
+  { "fa2", 45 },
+  { "fa3", 46 },
+  { "fa4", 47 },
+  { "fa5", 48 },
+  { "fa6", 49 },
+  { "fa7", 50 },
+  { "fs2", 51 },
+  { "fs3", 52 },
+  { "fs4", 53 },
+  { "fs5", 54 },
+  { "fs6", 55 },
+  { "fs7", 56 },
+  { "fs8", 57 },
+  { "fs9", 58 },
+  { "fs10", 59 },
+  { "fs11", 60 },
+  { "ft8", 61 },
+  { "ft9", 62 },
+  { "ft10", 63 },
+  { "ft11", 64 },
+#define DECLARE_CSR(name, num) { #name, (num) + 65 },
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+};
+
+static enum auto_boolean use_compressed_breakpoints;
+/*
+static void
+show_use_compressed_breakpoints (struct ui_file *file, int from_tty,
+			    struct cmd_list_element *c,
+			    const char *value)
+{
+  fprintf_filtered (file,
+		    _("Debugger's behavior regarding "
+		      "compressed breakpoints is %s.\n"),
+		    value);
+}
+*/
+
+static struct cmd_list_element *setriscvcmdlist = NULL;
+static struct cmd_list_element *showriscvcmdlist = NULL;
+
+static void
+show_riscv_command (char *args, int from_tty)
+{
+  help_list (showriscvcmdlist, "show riscv ", all_commands, gdb_stdout);
+}
+
+static void
+set_riscv_command (char *args, int from_tty)
+{
+  printf_unfiltered
+    ("\"set riscv\" must be followed by an appropriate subcommand.\n");
+  help_list (setriscvcmdlist, "set riscv ", all_commands, gdb_stdout);
+}
+
+/* Implement the breakpoint_kind_from_pc gdbarch method.  */
+
+static int
+riscv_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
+{
+  if (use_compressed_breakpoints == AUTO_BOOLEAN_AUTO) {
+    if (gdbarch_tdep (gdbarch)->supports_compressed_isa == AUTO_BOOLEAN_AUTO)
+    {
+      /* TODO: Because we try to read misa, it is not possible to set a
+         breakpoint before connecting to a live target. A suggested workaround is
+         to look at the ELF file in this case.  */
+      struct frame_info *frame = get_current_frame ();
+      uint32_t misa = get_frame_register_unsigned (frame, RISCV_CSR_MISA_REGNUM);
+      if (misa & (1<<2))
+        gdbarch_tdep (gdbarch)->supports_compressed_isa = AUTO_BOOLEAN_TRUE;
+      else
+        gdbarch_tdep (gdbarch)->supports_compressed_isa = AUTO_BOOLEAN_FALSE;
+    }
+
+    if (gdbarch_tdep (gdbarch)->supports_compressed_isa == AUTO_BOOLEAN_TRUE)
+      return 2;
+    else
+      return 4;
+  } else if (use_compressed_breakpoints == AUTO_BOOLEAN_TRUE) {
+    return 2;
+  } else {
+    return 4;
+  }
+}
+
+/* Implement the sw_breakpoint_from_kind gdbarch method.  */
+
+static const gdb_byte *
+riscv_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
+{
+  static const gdb_byte ebreak[] = { 0x73, 0x00, 0x10, 0x00, };
+  static const gdb_byte c_ebreak[] = { 0x02, 0x90 };
+
+  *size = kind;
+  switch (kind)
+    {
+    case 2:
+      return c_ebreak;
+    case 4:
+      return ebreak;
+    default:
+      gdb_assert(0);
+    }
+}
+
+static struct value *
+value_of_riscv_user_reg (struct frame_info *frame, const void *baton)
+{
+  const int *reg_p = (const int *)baton;
+
+  return value_of_register (*reg_p, frame);
+}
+
+static const char *
+register_name (struct gdbarch *gdbarch,
+	       int regnum,
+	       int prefer_alias)
+{
+  int i;
+  static char buf[20];
+
+  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+    return tdesc_register_name (gdbarch, regnum);
+  /* Prefer to use the alias. */
+  if (prefer_alias &&
+      regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_REGNUM)
+    {
+      for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i)
+	if (regnum == riscv_register_aliases[i].regnum)
+	  return riscv_register_aliases[i].name;
+    }
+
+  if (regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
+      return riscv_gdb_reg_names[regnum];
+
+  if (regnum >= RISCV_FIRST_CSR_REGNUM && regnum <= RISCV_LAST_CSR_REGNUM)
+    {
+      sprintf(buf, "csr%d", regnum - RISCV_FIRST_CSR_REGNUM);
+      return buf;
+    }
+
+  if (regnum == RISCV_PRIV_REGNUM)
+    {
+      return "priv";
+    }
+
+  return NULL;
+}
+
+/* Implement the register_name gdbarch method.  */
+
+static const char *
+riscv_register_name (struct gdbarch *gdbarch,
+		     int regnum)
+{
+  return register_name(gdbarch, regnum, 0);
+}
+
+/* Reads a function return value of type TYPE.  */
+
+static void
+riscv_extract_return_value (struct type *type,
+			    struct regcache *regs,
+			    gdb_byte *dst,
+			    int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regs);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int regsize = riscv_isa_regsize (gdbarch);
+  bfd_byte *valbuf = dst;
+  int len = TYPE_LENGTH (type);
+  int st_len = std::min (regsize, len);
+  ULONGEST tmp;
+
+  gdb_assert (len <= 2 * regsize);
+
+  while (len > 0)
+    {
+      regcache_cooked_read_unsigned (regs, regnum++, &tmp);
+      store_unsigned_integer (valbuf, st_len, byte_order, tmp);
+      len -= regsize;
+      valbuf += regsize;
+    }
+}
+
+/* Write into appropriate registers a function return value of type
+   TYPE, given in virtual format.  */
+
+static void
+riscv_store_return_value (struct type *type,
+			  struct regcache *regs,
+			  const gdb_byte *src,
+			  int regnum)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regs);
+  int regsize = riscv_isa_regsize (gdbarch);
+  const bfd_byte *valbuf = src;
+
+  /* Integral values greater than one word are stored in consecutive
+     registers starting with R0.  This will always be a multiple of
+     the register size.  */
+
+  int len = TYPE_LENGTH (type);
+
+  gdb_assert (len <= 2 * regsize);
+
+  while (len > 0)
+    {
+      regcache_cooked_write (regs, regnum++, valbuf);
+      len -= regsize;
+      valbuf += regsize;
+    }
+}
+
+/* Implement the return_value gdbarch method.  */
+
+static enum return_value_convention
+riscv_return_value (struct gdbarch  *gdbarch,
+		    struct value *function,
+		    struct type *type,
+		    struct regcache *regcache,
+		    gdb_byte *readbuf,
+		    const gdb_byte *writebuf)
+{
+  enum type_code rv_type = TYPE_CODE (type);
+  unsigned int rv_size = TYPE_LENGTH (type);
+  int fp, regnum;
+  ULONGEST tmp;
+
+  /* Paragraph on return values taken from RISC-V specification (post v2.0):
+
+     Values are returned from functions in integer registers a0 and a1 and
+     floating-point registers fa0 and fa1.  Floating-point values are returned
+     in floating-point registers only if they are primitives or members of a
+     struct consisting of only one or two floating-point values.  Other return
+     values that fit into two pointer-words are returned in a0 and a1.  Larger
+     return values are passed entirely in memory; the caller allocates this
+     memory region and passes a pointer to it as an implicit first parameter
+     to the callee.  */
+
+  /* Deal with struct/unions first that are passed via memory.  */
+  if (rv_size > 2 * riscv_isa_regsize (gdbarch))
+    {
+      if (readbuf || writebuf)
+	regcache_cooked_read_unsigned (regcache, RISCV_A0_REGNUM, &tmp);
+      if (readbuf)
+	read_memory (tmp, readbuf, rv_size);
+      if (writebuf)
+	write_memory (tmp, writebuf, rv_size);
+      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
+    }
+
+  /* Are we dealing with a floating point value?  */
+  fp = 0;
+  if (rv_type == TYPE_CODE_FLT)
+    fp = 1;
+  else if (rv_type == TYPE_CODE_STRUCT || rv_type == TYPE_CODE_UNION)
+    {
+      unsigned int rv_fields = TYPE_NFIELDS (type);
+
+      if (rv_fields == 1)
+	{
+	  struct type *fieldtype = TYPE_FIELD_TYPE (type, 0);
+	  if (TYPE_CODE (check_typedef (fieldtype)) == TYPE_CODE_FLT)
+	    fp = 1;
+	}
+      else if (rv_fields == 2)
+	{
+	  struct type *fieldtype0 = TYPE_FIELD_TYPE (type, 0);
+	  struct type *fieldtype1 = TYPE_FIELD_TYPE (type, 1);
+
+	  if (TYPE_CODE (check_typedef (fieldtype0)) == TYPE_CODE_FLT
+	      && TYPE_CODE (check_typedef (fieldtype1)) == TYPE_CODE_FLT)
+	    fp = 1;
+	}
+    }
+
+  /* Handle return value in a register.  */
+  regnum = fp ? RISCV_FA0_REGNUM : RISCV_A0_REGNUM;
+
+  if (readbuf)
+    riscv_extract_return_value (type, regcache, readbuf, regnum);
+
+  if (writebuf)
+    riscv_store_return_value (type, regcache, writebuf, regnum);
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the pseudo_register_read gdbarch method.  */
+
+static enum register_status
+riscv_pseudo_register_read (struct gdbarch *gdbarch,
+			    struct regcache *regcache,
+			    int regnum,
+			    gdb_byte *buf)
+{
+  return regcache_raw_read (regcache, regnum, buf);
+}
+
+/* Implement the pseudo_register_write gdbarch method.  */
+
+static void
+riscv_pseudo_register_write (struct gdbarch *gdbarch,
+			     struct regcache *regcache,
+			     int cookednum,
+			     const gdb_byte *buf)
+{
+  regcache_raw_write (regcache, cookednum, buf);
+}
+
+/* Implement the register_type gdbarch method.  */
+
+static struct type *
+riscv_register_type (struct gdbarch *gdbarch,
+		     int regnum)
+{
+  int regsize = riscv_isa_regsize (gdbarch);
+
+  if (regnum < RISCV_FIRST_FP_REGNUM)
+    {
+      /*
+       * GPRs and especially the PC are listed as unsigned so that gdb can
+       * interpret them as addresses without any problems. Specifically, if a
+       * user runs "x/i $pc" then they should see the instruction at the PC.
+       * But on a 32-bit system, with a signed PC of eg. 0x8000_0000, gdb will
+       * internally sign extend the value and then attempt to read from
+       * 0xffff_ffff_8000_0000, which it then concludes it can't read.
+       */
+      switch (regsize)
+	{
+	case 4:
+	  return builtin_type (gdbarch)->builtin_uint32;
+	case 8:
+	  return builtin_type (gdbarch)->builtin_uint64;
+	case 16:
+	  return builtin_type (gdbarch)->builtin_uint128;
+	default:
+	  internal_error (__FILE__, __LINE__,
+			  _("unknown isa regsize %i"), regsize);
+	}
+    }
+  else if (regnum <= RISCV_LAST_FP_REGNUM)
+    {
+      switch (regsize)
+	{
+	case 4:
+	  return builtin_type (gdbarch)->builtin_float;
+	case 8:
+	case 16:
+	  return builtin_type (gdbarch)->builtin_double;
+	default:
+	  internal_error (__FILE__, __LINE__,
+			  _("unknown isa regsize %i"), regsize);
+	}
+    }
+  else if (regnum == RISCV_PRIV_REGNUM)
+    {
+      return builtin_type (gdbarch)->builtin_int8;
+    }
+  else
+    {
+      if (regnum == RISCV_CSR_FFLAGS_REGNUM
+	  || regnum == RISCV_CSR_FRM_REGNUM
+	  || regnum == RISCV_CSR_FCSR_REGNUM)
+	return builtin_type (gdbarch)->builtin_int32;
+
+      switch (regsize)
+	{
+	case 4:
+	  return builtin_type (gdbarch)->builtin_int32;
+	case 8:
+	  return builtin_type (gdbarch)->builtin_int64;
+	case 16:
+	  return builtin_type (gdbarch)->builtin_int128;
+	default:
+	  internal_error (__FILE__, __LINE__,
+			  _("unknown isa regsize %i"), regsize);
+	}
+    }
+}
+
+static void
+riscv_print_fp_register (struct ui_file *file, struct frame_info *frame,
+			 int regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct value_print_options opts;
+  const char *regname;
+  value *val = get_frame_register_value(frame, regnum);
+
+  fprintf_filtered (file, "%-15s", gdbarch_register_name (gdbarch, regnum));
+
+  get_formatted_print_options (&opts, 'f');
+  val_print_scalar_formatted (value_type (val),
+			      value_embedded_offset (val),
+			      val,
+			      &opts, 0, file);
+}
+
+static void
+riscv_print_register_formatted (struct ui_file *file, struct frame_info *frame,
+				int regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  gdb_byte raw_buffer[MAX_REGISTER_SIZE];
+  struct value_print_options opts;
+
+  if (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
+    riscv_print_fp_register (file, frame, regnum);
+  else
+    {
+      /* Integer type.  */
+      int offset, size;
+      unsigned long long d;
+
+      if (!deprecated_frame_register_read (frame, regnum, raw_buffer))
+	{
+	  fprintf_filtered (file, "%-15s[Invalid]\n",
+			    register_name (gdbarch, regnum, 1));
+	  return;
+	}
+
+      fprintf_filtered (file, "%-15s", register_name (gdbarch, regnum, 1));
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	offset = register_size (gdbarch, regnum) - register_size (gdbarch, regnum);
+      else
+	offset = 0;
+
+      size = register_size (gdbarch, regnum);
+      get_formatted_print_options (&opts, 'x');
+      print_scalar_formatted (raw_buffer + offset,
+			      register_type (gdbarch, regnum), &opts,
+			      size == 8 ? 'g' : 'w', file);
+      fprintf_filtered (file, "\t");
+      if (size == 4 && riscv_isa_regsize (gdbarch) == 8)
+	fprintf_filtered (file, "\t");
+
+      if (regnum == RISCV_CSR_MSTATUS_REGNUM)
+	{
+	  if (size == 4)
+	    d = unpack_long (builtin_type (gdbarch)->builtin_uint32, raw_buffer);
+	  else if (size == 8)
+	    d = unpack_long (builtin_type (gdbarch)->builtin_uint64, raw_buffer);
+	  else
+	    internal_error (__FILE__, __LINE__, _("unknown size for mstatus"));
+	  unsigned xlen = size * 4;
+	  fprintf_filtered (file,
+			    "SD:%X VM:%02X MXR:%X PUM:%X MPRV:%X XS:%X "
+			    "FS:%X MPP:%x HPP:%X SPP:%X MPIE:%X HPIE:%X "
+			    "SPIE:%X UPIE:%X MIE:%X HIE:%X SIE:%X UIE:%X",
+			    (int)((d >> (xlen-1)) & 0x1),
+			    (int)((d >> 24) & 0x1f),
+			    (int)((d >> 19) & 0x1),
+			    (int)((d >> 18) & 0x1),
+			    (int)((d >> 17) & 0x1),
+			    (int)((d >> 15) & 0x3),
+			    (int)((d >> 13) & 0x3),
+			    (int)((d >> 11) & 0x3),
+			    (int)((d >> 9) & 0x3),
+			    (int)((d >> 8) & 0x1),
+			    (int)((d >> 7) & 0x1),
+			    (int)((d >> 6) & 0x1),
+			    (int)((d >> 5) & 0x1),
+			    (int)((d >> 4) & 0x1),
+			    (int)((d >> 3) & 0x1),
+			    (int)((d >> 2) & 0x1),
+			    (int)((d >> 1) & 0x1),
+			    (int)((d >> 0) & 0x1));
+	}
+      else if (regnum == RISCV_CSR_MISA_REGNUM)
+        {
+          int base;
+          if (size == 4) {
+            d = unpack_long (builtin_type (gdbarch)->builtin_uint32, raw_buffer);
+            base = d >> 30;
+          } else if (size == 8) {
+            d = unpack_long (builtin_type (gdbarch)->builtin_uint64, raw_buffer);
+            base = d >> 62;
+          } else {
+            internal_error (__FILE__, __LINE__, _("unknown size for misa"));
+          }
+          unsigned xlen = 16;
+          for (; base > 0; base--) {
+            xlen *= 2;
+          }
+	  fprintf_filtered (file, "RV%d", xlen);
+
+          for (unsigned i = 0; i < 26; i++) {
+            if (d & (1<<i)) {
+              fprintf_filtered (file, "%c", 'A' + i);
+            }
+          }
+        }
+      else if (regnum == RISCV_CSR_FCSR_REGNUM
+	       || regnum == RISCV_CSR_FFLAGS_REGNUM
+	       || regnum == RISCV_CSR_FRM_REGNUM)
+	{
+	  d = unpack_long (builtin_type (gdbarch)->builtin_int32, raw_buffer);
+
+	  if (regnum != RISCV_CSR_FRM_REGNUM)
+	    fprintf_filtered (file, "RD:%01X NV:%d DZ:%d OF:%d UF:%d NX:%d   ",
+			      (int)((d >> 5) & 0x7),
+			      (int)((d >> 4) & 0x1),
+			      (int)((d >> 3) & 0x1),
+			      (int)((d >> 2) & 0x1),
+			      (int)((d >> 1) & 0x1),
+			      (int)((d >> 0) & 0x1));
+
+	  if (regnum != RISCV_CSR_FFLAGS_REGNUM)
+	    {
+	      static const char * const sfrm[] = {
+		"RNE (round to nearest; ties to even)",
+		"RTZ (Round towards zero)",
+		"RDN (Round down towards -∞)",
+		"RUP (Round up towards +∞)",
+		"RMM (Round to nearest; tiest to max magnitude)",
+		"INVALID[5]",
+		"INVALID[6]",
+		"dynamic rounding mode",
+	      };
+	      int frm = ((regnum == RISCV_CSR_FCSR_REGNUM) ? (d >> 5) : d) & 0x3;
+
+	      fprintf_filtered (file, "FRM:%i [%s]", frm, sfrm[frm]);
+	    }
+	}
+      else if (regnum == RISCV_PRIV_REGNUM)
+        {
+          uint8_t priv = raw_buffer[0];
+          if (priv >= 0 && priv < 4)
+            {
+              static const char * const sprv[] = {
+                "User/Application",
+                "Supervisor",
+                "Hypervisor",
+                "Machine"
+              };
+              fprintf_filtered (file, "prv:%d [%s]", priv, sprv[priv]);
+            }
+          else
+            {
+              fprintf_filtered (file, "prv:%d [INVALID]", priv);
+            }
+        }
+      else
+	{
+	  get_formatted_print_options (&opts, 'd');
+	  print_scalar_formatted (raw_buffer + offset,
+				  register_type (gdbarch, regnum),
+				  &opts, 0, file);
+	}
+    }
+  fprintf_filtered (file, "\n");
+}
+
+/* Implement the register_reggroup_p gdbarch method.  */
+
+static int
+riscv_register_reggroup_p (struct gdbarch  *gdbarch,
+			   int regnum,
+			   struct reggroup *reggroup)
+{
+  int float_p;
+  int raw_p;
+  unsigned int i;
+
+  /* Used by 'info registers' and 'info registers <groupname>'.  */
+
+  if (gdbarch_register_name (gdbarch, regnum) == NULL
+      || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
+    return 0;
+
+  if (reggroup == all_reggroup) {
+    if (regnum < RISCV_FIRST_CSR_REGNUM || regnum == RISCV_PRIV_REGNUM)
+      return 1;
+    /* Only include CSRs that have aliases.  */
+    for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i) {
+	if (regnum == riscv_register_aliases[i].regnum)
+          return 1;
+    }
+    return 0;
+  } else if (reggroup == float_reggroup)
+    return (regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
+	    || (regnum == RISCV_CSR_FCSR_REGNUM
+	        || regnum == RISCV_CSR_FFLAGS_REGNUM
+	        || regnum == RISCV_CSR_FRM_REGNUM);
+  else if (reggroup == general_reggroup)
+    return regnum < RISCV_FIRST_FP_REGNUM;
+  else if (reggroup == restore_reggroup || reggroup == save_reggroup)
+    return regnum <= RISCV_LAST_FP_REGNUM;
+  else if (reggroup == system_reggroup) {
+    if (regnum == RISCV_PRIV_REGNUM)
+      return 1;
+    if (regnum < RISCV_FIRST_CSR_REGNUM || regnum > RISCV_LAST_CSR_REGNUM)
+      return 0;
+    /* Only include CSRs that have aliases.  */
+    for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i) {
+	if (regnum == riscv_register_aliases[i].regnum)
+          return 1;
+    }
+    return 0;
+  } else if (reggroup == vector_reggroup)
+    return 0;
+  else
+    internal_error (__FILE__, __LINE__, _("unhandled reggroup"));
+}
+
+/* Implement the print_registers_info gdbarch method.  */
+
+static void
+riscv_print_registers_info (struct gdbarch    *gdbarch,
+			    struct ui_file    *file,
+			    struct frame_info *frame,
+			    int                regnum,
+			    int                all)
+{
+  /* Use by 'info all-registers'.  */
+  struct reggroup *reggroup;
+
+  if (regnum != -1)
+    {
+      /* Print one specified register.  */
+      gdb_assert (regnum <= RISCV_LAST_REGNUM);
+      if (NULL == register_name (gdbarch, regnum, 1))
+        error (_("Not a valid register for the current processor type"));
+      riscv_print_register_formatted (file, frame, regnum);
+      return;
+    }
+
+  if (all)
+    reggroup = all_reggroup;
+  else
+    reggroup = general_reggroup;
+  for (regnum = 0; regnum <= RISCV_LAST_REGNUM; ++regnum)
+    {
+      /* Zero never changes, so might as well hide by default.  */
+      if (regnum == RISCV_ZERO_REGNUM && !all)
+        continue;
+      if (riscv_register_reggroup_p(gdbarch, regnum, reggroup))
+        riscv_print_register_formatted (file, frame, regnum);
+    }
+}
+
+static ULONGEST
+riscv_fetch_instruction (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order_for_code (gdbarch);
+  gdb_byte buf[8];
+  int instlen, status;
+
+  /* All insns are at least 16 bits.  */
+  status = target_read_memory (addr, buf, 2);
+  if (status)
+    memory_error (TARGET_XFER_E_IO, addr);
+
+  /* If we need more, grab it now.  */
+  instlen = riscv_insn_length (buf[0]);
+  if (instlen > sizeof (buf))
+    internal_error (__FILE__, __LINE__, _("%s: riscv_insn_length returned %i"),
+		    __func__, instlen);
+  else if (instlen > 2)
+    {
+      status = target_read_memory (addr + 2, buf + 2, instlen - 2);
+      if (status)
+	memory_error (TARGET_XFER_E_IO, addr + 2);
+    }
+
+  return extract_unsigned_integer (buf, instlen, byte_order);
+}
+
+static void
+set_reg_offset (struct gdbarch *gdbarch, struct riscv_frame_cache *this_cache,
+		int regnum, CORE_ADDR offset)
+{
+  if (this_cache != NULL && this_cache->saved_regs[regnum].addr == -1)
+    this_cache->saved_regs[regnum].addr = offset;
+}
+
+static void
+reset_saved_regs (struct gdbarch *gdbarch, struct riscv_frame_cache *this_cache)
+{
+  const int num_regs = gdbarch_num_regs (gdbarch);
+  int i;
+
+  if (this_cache == NULL || this_cache->saved_regs == NULL)
+    return;
+
+  for (i = 0; i < num_regs; ++i)
+    this_cache->saved_regs[i].addr = 0;
+}
+
+static int riscv_decode_register_index(unsigned long opcode, int offset)
+{
+    return (opcode >> offset) & 0x1F;
+}
+
+static CORE_ADDR
+riscv_scan_prologue (struct gdbarch *gdbarch,
+		     CORE_ADDR start_pc, CORE_ADDR limit_pc,
+		     struct frame_info *this_frame,
+		     struct riscv_frame_cache *this_cache)
+{
+  CORE_ADDR cur_pc;
+  CORE_ADDR frame_addr = 0;
+  CORE_ADDR sp;
+  long frame_offset;
+  int frame_reg = RISCV_SP_REGNUM;
+
+  CORE_ADDR end_prologue_addr = 0;
+  int seen_sp_adjust = 0;
+  int load_immediate_bytes = 0;
+
+  /* Can be called when there's no process, and hence when there's no THIS_FRAME.  */
+  if (this_frame != NULL)
+    sp = get_frame_register_signed (this_frame, RISCV_SP_REGNUM);
+  else
+    sp = 0;
+
+  if (limit_pc > start_pc + 200)
+    limit_pc = start_pc + 200;
+
+ restart:
+
+  frame_offset = 0;
+  /* TODO: Handle compressed extensions.  */
+  for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4)
+    {
+      ULONGEST inst;
+      unsigned long opcode;
+      int reg, rs1, imm12, rs2, offset12, funct3;
+
+      /* Fetch the instruction.  */
+      inst = riscv_fetch_instruction (gdbarch, cur_pc);
+
+      /* Decode the instruction.  These offsets are defined in the RISC-V ISA
+       * manual.  */
+      reg = riscv_decode_register_index(inst, 7);
+      rs1 = riscv_decode_register_index(inst, 15);
+      rs2 = riscv_decode_register_index(inst, 20);
+      imm12 = (inst >> 20) & 0xFFF;
+      offset12 = (((inst >> 25) & 0x7F) << 5) + ((inst >> 7) & 0x1F);
+
+      /* Look for common stack adjustment insns.  */
+      if ((is_addi_insn(inst) || is_addiw_insn(inst))
+	  && reg == RISCV_SP_REGNUM && rs1 == RISCV_SP_REGNUM)
+	{
+	  /* addi sp, sp, -i */
+	  /* addiw sp, sp, -i */
+	  if (imm12 & 0x800)
+	    frame_offset += 0x1000 - imm12;
+	  else
+	    break;
+	  seen_sp_adjust = 1;
+	}
+      else if (is_sw_insn(inst) && rs1 == RISCV_SP_REGNUM)
+	{
+	  /* sw reg, offset(sp) */
+	  set_reg_offset (gdbarch, this_cache, rs1, sp + offset12);
+	}
+      else if (is_sd_insn(inst) && rs1 == RISCV_SP_REGNUM)
+	{
+	  /* sd reg, offset(sp) */
+	  set_reg_offset (gdbarch, this_cache, rs1, sp + offset12);
+	}
+      else if (is_addi_insn(inst) && reg == RISCV_FP_REGNUM
+	       && rs1 == RISCV_SP_REGNUM)
+	{
+	  /* addi s0, sp, size */
+	  if ((long)imm12 != frame_offset)
+	    frame_addr = sp + imm12;
+	}
+      else if (this_frame && frame_reg == RISCV_SP_REGNUM)
+	{
+	  unsigned alloca_adjust;
+
+	  frame_reg = RISCV_FP_REGNUM;
+	  frame_addr = get_frame_register_signed (this_frame, RISCV_FP_REGNUM);
+
+	  alloca_adjust = (unsigned)(frame_addr - (sp - imm12));
+	  if (alloca_adjust > 0)
+	    {
+	      sp += alloca_adjust;
+	      reset_saved_regs (gdbarch, this_cache);
+	      goto restart;
+	    }
+	}
+      else if ((is_add_insn(inst) || is_addw_insn(inst))
+	       && reg == RISCV_FP_REGNUM && rs1 == RISCV_SP_REGNUM
+               && rs2 == RISCV_ZERO_REGNUM)
+	{
+	  /* add s0, sp, 0 */
+	  /* addw s0, sp, 0 */
+	  if (this_frame && frame_reg == RISCV_SP_REGNUM)
+	    {
+	      unsigned alloca_adjust;
+	      frame_reg = RISCV_FP_REGNUM;
+	      frame_addr = get_frame_register_signed (this_frame,
+						      RISCV_FP_REGNUM);
+
+	      alloca_adjust = (unsigned)(frame_addr - sp);
+	      if (alloca_adjust > 0)
+		{
+		  sp = frame_addr;
+		  reset_saved_regs (gdbarch, this_cache);
+		  goto restart;
+		}
+	    }
+	}
+      else if (is_sw_insn(inst) && rs1 == RISCV_FP_REGNUM)
+	{
+	  /* sw reg, offset(s0) */
+	  set_reg_offset (gdbarch, this_cache, rs1, frame_addr + offset12);
+	}
+      else if (reg == RISCV_GP_REGNUM
+	       && (is_auipc_insn(inst)
+                   || is_lui_insn(inst)
+		   || (is_addi_insn(inst) && rs1 == RISCV_GP_REGNUM)
+		   || (is_add_insn(inst) && (rs1 == RISCV_GP_REGNUM
+					  || rs2 == RISCV_GP_REGNUM))))
+	{
+	  /* auipc gp, n */
+	  /* addi gp, gp, n */
+	  /* add gp, gp, reg */
+	  /* add gp, reg, gp */
+	  /* lui gp, n */
+	  /* These instructions are part of the prologue, but we don't need to
+	     do anything special to handle them.  */
+	}
+      else
+	{
+	  if (end_prologue_addr == 0)
+	    end_prologue_addr = cur_pc;
+	}
+    }
+
+  if (this_cache != NULL)
+    {
+      this_cache->base = get_frame_register_signed (this_frame, frame_reg)
+	+ frame_offset;
+      this_cache->saved_regs[RISCV_PC_REGNUM] =
+	this_cache->saved_regs[RISCV_RA_REGNUM];
+    }
+
+  if (end_prologue_addr == 0)
+    end_prologue_addr = cur_pc;
+
+  if (load_immediate_bytes && !seen_sp_adjust)
+    end_prologue_addr -= load_immediate_bytes;
+
+  return end_prologue_addr;
+}
+
+/* Implement the riscv_skip_prologue gdbarch method.  */
+
+static CORE_ADDR
+riscv_skip_prologue (struct gdbarch *gdbarch,
+		     CORE_ADDR       pc)
+{
+  CORE_ADDR limit_pc;
+  CORE_ADDR func_addr;
+
+  /* See if we can determine the end of the prologue via the symbol table.
+     If so, then return either PC, or the PC after the prologue, whichever
+     is greater.  */
+  if (find_pc_partial_function (pc, NULL, &func_addr, NULL))
+    {
+      CORE_ADDR post_prologue_pc = skip_prologue_using_sal (gdbarch, func_addr);
+      if (post_prologue_pc != 0)
+	return std::max (pc, post_prologue_pc);
+    }
+
+  /* Can't determine prologue from the symbol table, need to examine
+     instructions.  */
+
+  /* Find an upper limit on the function prologue using the debug information.
+     If the debug information could not be used to provide that bound, then use
+     an arbitrary large number as the upper bound.  */
+  limit_pc = skip_prologue_using_sal (gdbarch, pc);
+  if (limit_pc == 0)
+    limit_pc = pc + 100;   /* MAGIC! */
+
+  return riscv_scan_prologue (gdbarch, pc, limit_pc, NULL, NULL);
+}
+
+static CORE_ADDR
+riscv_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr,
+		       struct value **args, int nargs, struct type *value_type,
+		       CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+		       struct regcache *regcache)
+{
+  *bp_addr = sp;
+  *real_pc = funaddr;
+
+  /* Keep the stack aligned.  */
+  return sp - 16;
+}
+
+static CORE_ADDR
+riscv_push_dummy_call (struct gdbarch *gdbarch,
+		       struct value *function,
+		       struct regcache *regcache,
+		       CORE_ADDR bp_addr,
+		       int nargs,
+		       struct value **args,
+		       CORE_ADDR sp,
+		       int struct_return,
+		       CORE_ADDR struct_addr)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  gdb_byte buf[4];
+  int i;
+  CORE_ADDR func_addr = find_function_addr (function, NULL);
+
+  /* Push excess arguments in reverse order.  */
+
+  for (i = nargs; i >= 8; --i)
+    {
+      struct type *value_type = value_enclosing_type (args[i]);
+      int container_len = align_up (TYPE_LENGTH (value_type), 3);
+
+      sp -= container_len;
+      write_memory (sp, value_contents_writeable (args[i]), container_len);
+    }
+
+  /* Initialize argument registers.  */
+
+  for (i = 0; i < nargs && i < 8; ++i)
+    {
+      struct type *value_type = value_enclosing_type (args[i]);
+      const gdb_byte *arg_bits = value_contents_all (args[i]);
+      int regnum = (TYPE_CODE (value_type) == TYPE_CODE_FLT
+		    ? RISCV_FA0_REGNUM : RISCV_A0_REGNUM);
+
+      regcache_cooked_write_unsigned
+	(regcache, regnum + i,
+	 extract_unsigned_integer
+	   (arg_bits, riscv_isa_regsize(gdbarch), byte_order));
+    }
+
+  /* Store struct value address.  */
+
+  if (struct_return)
+    regcache_cooked_write_unsigned (regcache, RISCV_A0_REGNUM, struct_addr);
+
+  /* Set the dummy return value to bp_addr.
+     A dummy breakpoint will be setup to execute the call.  */
+
+  regcache_cooked_write_unsigned (regcache, RISCV_RA_REGNUM, bp_addr);
+
+  /* Finally, update the stack pointer.  */
+
+  regcache_cooked_write_unsigned (regcache, RISCV_SP_REGNUM, sp);
+
+  return sp;
+}
+
+/* Implement the frame_align gdbarch method.  */
+
+static CORE_ADDR
+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));
+}
+
+static struct trad_frame_cache *
+riscv_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  CORE_ADDR pc;
+  CORE_ADDR start_addr;
+  CORE_ADDR stack_addr;
+  struct trad_frame_cache *this_trad_cache;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
+  if ((*this_cache) != NULL)
+    return (struct trad_frame_cache *) *this_cache;
+  this_trad_cache = trad_frame_cache_zalloc (this_frame);
+  (*this_cache) = this_trad_cache;
+
+  trad_frame_set_reg_realreg (this_trad_cache, gdbarch_pc_regnum (gdbarch),
+			      RISCV_RA_REGNUM);
+
+  pc = get_frame_pc (this_frame);
+  find_pc_partial_function (pc, NULL, &start_addr, NULL);
+  stack_addr = get_frame_register_signed (this_frame, RISCV_SP_REGNUM);
+  trad_frame_set_id (this_trad_cache, frame_id_build (stack_addr, start_addr));
+
+  trad_frame_set_this_base (this_trad_cache, stack_addr);
+
+  return this_trad_cache;
+}
+
+static void
+riscv_frame_this_id (struct frame_info *this_frame,
+		     void              **prologue_cache,
+		     struct frame_id   *this_id)
+{
+  struct trad_frame_cache *info = riscv_frame_cache (this_frame, prologue_cache);
+  trad_frame_get_id (info, this_id);
+}
+
+static struct value *
+riscv_frame_prev_register (struct frame_info *this_frame,
+			   void              **prologue_cache,
+			   int                regnum)
+{
+  struct trad_frame_cache *info = riscv_frame_cache (this_frame, prologue_cache);
+  return trad_frame_get_register (info, this_frame, regnum);
+}
+
+static const struct frame_unwind riscv_frame_unwind =
+{
+  /*.type          =*/ NORMAL_FRAME,
+  /*.stop_reason   =*/ default_frame_unwind_stop_reason,
+  /*.this_id       =*/ riscv_frame_this_id,
+  /*.prev_register =*/ riscv_frame_prev_register,
+  /*.unwind_data   =*/ NULL,
+  /*.sniffer       =*/ default_frame_sniffer,
+  /*.dealloc_cache =*/ NULL,
+  /*.prev_arch     =*/ NULL,
+};
+
+static struct gdbarch *
+riscv_gdbarch_init (struct gdbarch_info info,
+		    struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  const struct bfd_arch_info *binfo = info.bfd_arch_info;
+
+  int abi, i;
+
+  /* For now, base the abi on the elf class.  */
+  /* Allow the ELF class to override the register size. Ideally the target
+   * (OpenOCD/spike/...) would communicate the register size to gdb instead. */
+  abi = RISCV_ABI_FLAG_RV32I;
+  if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    {
+      unsigned char eclass = elf_elfheader (info.abfd)->e_ident[EI_CLASS];
+
+      if (eclass == ELFCLASS32)
+	abi = RISCV_ABI_FLAG_RV32I;
+      else if (eclass == ELFCLASS64)
+	abi = RISCV_ABI_FLAG_RV64I;
+      else
+        internal_error (__FILE__, __LINE__, _("unknown ELF header class %d"), eclass);
+    }
+  else
+    {
+      if (binfo->bits_per_word == 32)
+        abi = RISCV_ABI_FLAG_RV32I;
+      else if (binfo->bits_per_word == 64)
+        abi = RISCV_ABI_FLAG_RV64I;
+      else
+        internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"),
+            binfo->bits_per_word);
+    }
+
+  /* Find a candidate among the list of pre-declared architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    if (gdbarch_tdep (arches->gdbarch)->riscv_abi == abi)
+      return arches->gdbarch;
+
+  /* None found, so create a new architecture from the information provided.
+     Can't initialize all the target dependencies until we actually know which
+     target we are talking to, but put in some defaults for now.  */
+
+  tdep = (struct gdbarch_tdep *) xmalloc (sizeof *tdep);
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  tdep->riscv_abi = abi;
+  tdep->supports_compressed_isa = AUTO_BOOLEAN_AUTO;
+
+  /* Target data types.  */
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 32);
+  set_gdbarch_long_bit (gdbarch, riscv_isa_regsize (gdbarch) * 8);
+  set_gdbarch_float_bit (gdbarch, 32);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 128);
+  set_gdbarch_ptr_bit (gdbarch, riscv_isa_regsize (gdbarch) * 8);
+  set_gdbarch_char_signed (gdbarch, 1);
+
+  /* Information about the target architecture.  */
+  set_gdbarch_return_value (gdbarch, riscv_return_value);
+  set_gdbarch_breakpoint_kind_from_pc (gdbarch, riscv_breakpoint_kind_from_pc);
+  set_gdbarch_sw_breakpoint_from_kind (gdbarch, riscv_sw_breakpoint_from_kind);
+  set_gdbarch_print_insn (gdbarch, print_insn_riscv);
+
+  /* Register architecture.  */
+  set_gdbarch_pseudo_register_read (gdbarch, riscv_pseudo_register_read);
+  set_gdbarch_pseudo_register_write (gdbarch, riscv_pseudo_register_write);
+  set_gdbarch_num_regs (gdbarch, RISCV_NUM_REGS);
+  set_gdbarch_num_pseudo_regs (gdbarch, RISCV_NUM_REGS);
+  set_gdbarch_sp_regnum (gdbarch, RISCV_SP_REGNUM);
+  set_gdbarch_pc_regnum (gdbarch, RISCV_PC_REGNUM);
+  set_gdbarch_ps_regnum (gdbarch, RISCV_FP_REGNUM);
+  set_gdbarch_deprecated_fp_regnum (gdbarch, RISCV_FP_REGNUM);
+
+  /* Functions to supply register information.  */
+  set_gdbarch_register_name (gdbarch, riscv_register_name);
+  set_gdbarch_register_type (gdbarch, riscv_register_type);
+  set_gdbarch_print_registers_info (gdbarch, riscv_print_registers_info);
+  set_gdbarch_register_reggroup_p (gdbarch, riscv_register_reggroup_p);
+
+  /* Functions to analyze frames.  */
+  set_gdbarch_skip_prologue (gdbarch, riscv_skip_prologue);
+  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.  */
+  dwarf2_append_unwinders (gdbarch);
+  frame_unwind_append_unwinder (gdbarch, &riscv_frame_unwind);
+
+  /* Check any target description for validity.  */
+  if (tdesc_has_registers (info.target_desc))
+    {
+      const struct tdesc_feature *feature;
+      struct tdesc_arch_data *tdesc_data;
+      int valid_p;
+
+      feature = tdesc_find_feature (info.target_desc, "org.gnu.gdb.riscv.cpu");
+      if (feature == NULL)
+	goto no_tdata;
+
+      tdesc_data = tdesc_data_alloc ();
+
+      valid_p = 1;
+      for (i = RISCV_ZERO_REGNUM; i <= RISCV_LAST_FP_REGNUM; ++i)
+        valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+                                            riscv_gdb_reg_names[i]);
+      for (i = RISCV_FIRST_CSR_REGNUM; i <= RISCV_LAST_CSR_REGNUM; ++i)
+        {
+          char buf[20];
+          sprintf (buf, "csr%d", i - RISCV_FIRST_CSR_REGNUM);
+          valid_p &= tdesc_numbered_register (feature, tdesc_data, i, buf);
+        }
+
+      valid_p &= tdesc_numbered_register (feature, tdesc_data, i++, "priv");
+
+      if (!valid_p)
+	tdesc_data_cleanup (tdesc_data);
+      else
+	tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
+    }
+ no_tdata:
+
+  for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i)
+    user_reg_add (gdbarch, riscv_register_aliases[i].name,
+		  value_of_riscv_user_reg, &riscv_register_aliases[i].regnum);
+
+  return gdbarch;
+}
+
+extern initialize_file_ftype _initialize_riscv_tdep; /* -Wmissing-prototypes */
+
+void
+_initialize_riscv_tdep (void)
+{
+  gdbarch_register (bfd_arch_riscv, riscv_gdbarch_init, NULL);
+
+  /* Add root prefix command for all "set riscv"/"show riscv" commands.  */
+  add_prefix_cmd ("riscv", no_class, set_riscv_command,
+      _("RISC-V specific commands."),
+      &setriscvcmdlist, "set riscv ", 0, &setlist);
+
+  add_prefix_cmd ("riscv", no_class, show_riscv_command,
+      _("RISC-V specific commands."),
+      &showriscvcmdlist, "show riscv ", 0, &showlist);
+
+  use_compressed_breakpoints = AUTO_BOOLEAN_AUTO;
+  add_setshow_auto_boolean_cmd ("use_compressed_breakpoints", no_class,
+      &use_compressed_breakpoints,
+      _("Configure whether to use compressed breakpoints."),
+      _("Show whether to use compressed breakpoints."),
+      _("\
+Debugging compressed code requires compressed breakpoints to be used. If left\n\
+to 'auto' then gdb will use them if $misa indicates the C extension is\n\
+supported. If that doesn't give the correct behavior, then this option can be\n\
+used."),
+      NULL,
+      NULL,
+      &setriscvcmdlist,
+      &showriscvcmdlist);
+}
diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
new file mode 100644
index 0000000..f2e6b9d
--- /dev/null
+++ b/gdb/riscv-tdep.h
@@ -0,0 +1,96 @@
+/* Target-dependent header for the RISC-V architecture, for GDB, the GNU Debugger.
+
+   Copyright (C) 2002-2015 Free Software Foundation, Inc.
+
+   Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
+   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
+   and by Todd Snyder <todd@bluespec.com>
+   and by Mike Frysinger <vapier@gentoo.org>.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef RISCV_TDEP_H
+#define RISCV_TDEP_H
+
+struct gdbarch;
+
+/* All the official RISC-V ABIs.  These mostly line up with mcpuid purely for
+   convenience.  */
+#define RISCV_ABI_FLAG_RV32I	(0x00000000)	/* 32-bit Integer GPRs.  */
+#define RISCV_ABI_FLAG_RV64I	(0x40000000)	/* 64-bit Integer GPRs.  */
+#define RISCV_ABI_FLAG_D	(1 << 3)	/* Double-Precision Floating-Point.  */
+#define RISCV_ABI_FLAG_F	(1 << 5)	/* Single-Precision Floating-Point.  */
+
+#define IS_RV32I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV32I)
+#define IS_RV64I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV64I)
+
+#define HAS_FPU(x)	((x) & (RISCV_ABI_FLAG_D | RISCV_ABI_FLAG_F))
+
+enum {
+  RISCV_ZERO_REGNUM = 0,	/* Read-only register, always 0.  */
+  RISCV_RA_REGNUM = 1,		/* Return Address.  */
+  RISCV_SP_REGNUM = 2,		/* Stack Pointer.  */
+  RISCV_GP_REGNUM = 3,		/* Global Pointer.  */
+  RISCV_TP_REGNUM = 4,		/* Thread Pointer.  */
+  RISCV_FP_REGNUM = 8,		/* Frame Pointer.  */
+  RISCV_A0_REGNUM = 10,		/* First argument.  */
+  RISCV_A1_REGNUM = 11,		/* Second argument.  */
+  RISCV_PC_REGNUM = 32,		/* Program Counter.  */
+
+  RISCV_FIRST_FP_REGNUM = 33,	/* First Floating Point Register */
+  RISCV_FA0_REGNUM = 49,
+  RISCV_FA1_REGNUM = 50,
+  RISCV_LAST_FP_REGNUM = 64,	/* Last Floating Point Register */
+
+  RISCV_FIRST_CSR_REGNUM = 65,  /* First CSR */
+#define DECLARE_CSR(name, num) RISCV_ ## num ## _REGNUM = RISCV_LAST_FP_REGNUM + 1 + num,
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+  RISCV_LAST_CSR_REGNUM = 4160,
+
+  RISCV_PRIV_REGNUM = 4161,
+
+  /* Leave this as the last enum.  */
+  RISCV_NUM_REGS
+};
+
+#define RISCV_LAST_REGNUM (RISCV_NUM_REGS - 1)
+
+/* RISC-V specific per-architecture information.  */
+struct gdbarch_tdep
+{
+  int riscv_abi;
+  enum auto_boolean supports_compressed_isa;
+};
+
+static inline int
+riscv_isa_regsize (struct gdbarch *gdbarch)
+{
+  int abi = gdbarch_tdep (gdbarch)->riscv_abi;
+
+  switch (abi)
+    {
+      case RISCV_ABI_FLAG_RV32I:
+	return 4;
+      case RISCV_ABI_FLAG_RV64I:
+	return 8;
+      default:
+	internal_error (__FILE__, __LINE__, _("unknown abi %i"), abi);
+	return 4;
+    }
+}
+
+#endif /* RISCV_TDEP_H */
diff --git a/include/gdb/sim-riscv.h b/include/gdb/sim-riscv.h
new file mode 100644
index 0000000..932cf49
--- /dev/null
+++ b/include/gdb/sim-riscv.h
@@ -0,0 +1,98 @@
+/* This file defines the interface between the RISC-V simulator and GDB.
+
+   Copyright (C) 2005-2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Order has to match gdb riscv-tdep list.  */
+enum sim_riscv_regnum {
+  SIM_RISCV_ZERO_REGNUM = 0,
+  SIM_RISCV_RA_REGNUM,
+  SIM_RISCV_SP_REGNUM,
+  SIM_RISCV_GP_REGNUM,
+  SIM_RISCV_TP_REGNUM,
+  SIM_RISCV_T0_REGNUM,
+  SIM_RISCV_T1_REGNUM,
+  SIM_RISCV_T2_REGNUM,
+  SIM_RISCV_S0_REGNUM,
+#define SIM_RISCV_FP_REGNUM SIM_RISCV_S0_REGNUM
+  SIM_RISCV_S1_REGNUM,
+  SIM_RISCV_A0_REGNUM,
+  SIM_RISCV_A1_REGNUM,
+  SIM_RISCV_A2_REGNUM,
+  SIM_RISCV_A3_REGNUM,
+  SIM_RISCV_A4_REGNUM,
+  SIM_RISCV_A5_REGNUM,
+  SIM_RISCV_A6_REGNUM,
+  SIM_RISCV_A7_REGNUM,
+  SIM_RISCV_S2_REGNUM,
+  SIM_RISCV_S3_REGNUM,
+  SIM_RISCV_S4_REGNUM,
+  SIM_RISCV_S5_REGNUM,
+  SIM_RISCV_S6_REGNUM,
+  SIM_RISCV_S7_REGNUM,
+  SIM_RISCV_S8_REGNUM,
+  SIM_RISCV_S9_REGNUM,
+  SIM_RISCV_S10_REGNUM,
+  SIM_RISCV_S11_REGNUM,
+  SIM_RISCV_T3_REGNUM,
+  SIM_RISCV_T4_REGNUM,
+  SIM_RISCV_T5_REGNUM,
+  SIM_RISCV_T6_REGNUM,
+  SIM_RISCV_PC_REGNUM,
+  SIM_RISCV_FT0_REGNUM,
+#define SIM_RISCV_FIRST_FP_REGNUM SIM_RISCV_FT0_REGNUM
+  SIM_RISCV_FT1_REGNUM,
+  SIM_RISCV_FT2_REGNUM,
+  SIM_RISCV_FT3_REGNUM,
+  SIM_RISCV_FT4_REGNUM,
+  SIM_RISCV_FT5_REGNUM,
+  SIM_RISCV_FT6_REGNUM,
+  SIM_RISCV_FT7_REGNUM,
+  SIM_RISCV_FS0_REGNUM,
+  SIM_RISCV_FS1_REGNUM,
+  SIM_RISCV_FA0_REGNUM,
+  SIM_RISCV_FA1_REGNUM,
+  SIM_RISCV_FA2_REGNUM,
+  SIM_RISCV_FA3_REGNUM,
+  SIM_RISCV_FA4_REGNUM,
+  SIM_RISCV_FA5_REGNUM,
+  SIM_RISCV_FA6_REGNUM,
+  SIM_RISCV_FA7_REGNUM,
+  SIM_RISCV_FS2_REGNUM,
+  SIM_RISCV_FS3_REGNUM,
+  SIM_RISCV_FS4_REGNUM,
+  SIM_RISCV_FS5_REGNUM,
+  SIM_RISCV_FS6_REGNUM,
+  SIM_RISCV_FS7_REGNUM,
+  SIM_RISCV_FS8_REGNUM,
+  SIM_RISCV_FS9_REGNUM,
+  SIM_RISCV_FS10_REGNUM,
+  SIM_RISCV_FS11_REGNUM,
+  SIM_RISCV_FT8_REGNUM,
+  SIM_RISCV_FT9_REGNUM,
+  SIM_RISCV_FT10_REGNUM,
+  SIM_RISCV_FT11_REGNUM,
+#define SIM_RISCV_LAST_FP_REGNUM SIM_RISCV_FT11_REGNUM
+
+#define SIM_RISCV_FIRST_CSR_REGNUM SIM_RISCV_LAST_FP_REGNUM + 1
+#define DECLARE_CSR(name, num) SIM_RISCV_ ## num ## _REGNUM,
+#include "opcode/riscv-opc.h"
+#undef DECLARE_CSR
+#define SIM_RISCV_LAST_CSR_REGNUM SIM_RISCV_LAST_REGNUM - 1
+
+  SIM_RISCV_LAST_REGNUM
+};
-- 
2.10.2


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]