[1/2] RISC-V GDB Port

Message ID 1477179592-32501-2-git-send-email-palmer@dabbelt.com
State New, archived
Headers

Commit Message

Palmer Dabbelt Oct. 22, 2016, 11:39 p.m. UTC
  ---
 gdb/Makefile.in           |    5 +-
 gdb/config/riscv/linux.mh |   30 ++
 gdb/configure.ac          |    3 +
 gdb/configure.host        |    3 +
 gdb/configure.tgt         |   12 +
 gdb/infcmd.c              |    5 +-
 gdb/riscv-linux-nat.c     |   77 +++
 gdb/riscv-linux-tdep.c    |   83 +++
 gdb/riscv-linux-tdep.h    |   30 ++
 gdb/riscv-tdep.c          | 1292 +++++++++++++++++++++++++++++++++++++++++++++
 gdb/riscv-tdep.h          |  101 ++++
 include/gdb/sim-riscv.h   |   98 ++++
 12 files changed, 1735 insertions(+), 4 deletions(-)
 create mode 100644 gdb/config/riscv/linux.mh
 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
  

Comments

Yao Qi Nov. 3, 2016, 12:38 p.m. UTC | #1
Palmer Dabbelt <palmer@dabbelt.com> writes:

Hi Palmer,
you need a ChangeLog entry, and a news entry for this new gdb port.
There are some code style issues, please look at
https://sourceware.org/gdb/wiki/ContributionChecklist

> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 2c88434..e4e497b 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -691,7 +691,7 @@ ALL_TARGET_OBS = \
>  	nios2-tdep.o nios2-linux-tdep.o \
>  	nto-tdep.o \
>  	ppc-linux-tdep.o ppcfbsd-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o  \
> -	ppc-sysv-tdep.o ppc64-tdep.o rl78-tdep.o \
> +	ppc-sysv-tdep.o ppc64-tdep.o riscv-tdep.o rl78-tdep.o \

Miss riscv-linux-tdep.o?

>  	rs6000-aix-tdep.o rs6000-tdep.o solib-aix.o ppc-ravenscar-thread.o \
>  	rs6000-lynx178-tdep.o \
>  	rx-tdep.o \
> @@ -946,7 +946,7 @@ sparc64-tdep.h ppcobsd-tdep.h \
>  coff-pe-read.h parser-defs.h gdb_ptrace.h mips-linux-tdep.h \
>  m68k-tdep.h spu-tdep.h environ.h amd64-tdep.h \
>  doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h ppc64-tdep.h \
> -rs6000-tdep.h rs6000-aix-tdep.h \
> +riscv-tdep.h rs6000-tdep.h rs6000-aix-tdep.h \
>  common/gdb_locale.h arch-utils.h trad-frame.h gnu-nat.h \
>  language.h nbsd-tdep.h solib-svr4.h \
>  macroexp.h ui-file.h regcache.h tracepoint.h tracefile.h i386-tdep.h \
> @@ -1734,6 +1734,7 @@ ALLDEPFILES = \
>  	ravenscar-thread.c \
>  	remote-sim.c \
>  	dcache.c \
> +	riscv-tdep.c \

Miss riscv-linux-tdep.c?

>  	rl78-tdep.c \
>  	rs6000-nat.c rs6000-tdep.c solib-aix.c ppc-ravenscar-thread.c \
>  	rs6000-lynx178-tdep.c \
> diff --git a/gdb/config/riscv/linux.mh b/gdb/config/riscv/linux.mh
> new file mode 100644
> index 0000000..f68f371
> --- /dev/null
> +++ b/gdb/config/riscv/linux.mh
> @@ -0,0 +1,30 @@
> +#  Host: RISC-V based machine running GNU/Linux
> +#
> +#  Copyright (C) 2015 Free Software Foundation, Inc.

2016

> +#  Contributed by Albert Ou <albert@sifive.com>.
> +#

Albert Ou doesn't have FSF copyright assignment.

> --- a/gdb/configure.ac
> +++ b/gdb/configure.ac
> @@ -515,6 +515,9 @@ esac
>  # We might need to link with -lm; most simulators need it.
>  AC_CHECK_LIB(m, main)
>  
> +# The RISC-V simulator needs clock_gettime()
> +AC_SEARCH_LIBS([clock_gettime], [rt])
> +

I don't know much in sim configure, but this is about sim, so I think
this should be moved to sim/riscv/configure.ac.

> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 8e34b7e..4457304 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -3447,8 +3447,9 @@ otherwise all the threads in the program are stopped.  To \n\
>  interrupt all running threads in non-stop mode, use the -a option."));
>  
>    c = add_info ("registers", nofp_registers_info, _("\
> -List of integer registers and their contents, for selected stack frame.\n\
> -Register name as argument means describe only that register."));
> +Display registers and their contents, for the selected stack frame.\n\
> +Usage: info registers [all|register|register group] ...\n\
> +By default, the general register group will be shown."));

Please split this change out this patch.  Put it into a separated patch,
and give the reason why do you change that.


> diff --git a/gdb/riscv-linux-tdep.c b/gdb/riscv-linux-tdep.c
> new file mode 100644
> index 0000000..b66860c
> --- /dev/null
> +++ b/gdb/riscv-linux-tdep.c
> @@ -0,0 +1,83 @@
> +/* 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
> +};
> +

All gdbarch methods are should be documented like this,

/* Implement the iterate_over_regset_sections gdbarch method.  */

> +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.  */
> +  /* FIXME: This '0' should actually be a check to see if we're on
> +     rv32, but I can't figure out how to hook that up (it's in
> +     gdbarch_tdep, which we don't have here). */
> +  set_solib_svr4_fetch_link_map_offsets
> +    (gdbarch, (0) ?
> +      svr4_ilp32_fetch_link_map_offsets :
> +      svr4_lp64_fetch_link_map_offsets);

gdbarch_tdep (gdbarch)->riscv_abi can tell you rv32 or rv64 is used.

> --- /dev/null
> +++ b/gdb/riscv-tdep.c
> @@ -0,0 +1,1292 @@
> +/* 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>.

I don't find Todd Snyder's FSF copyright assignment.

> +
> +   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 "opcode/riscv-opc.h"
> +#include <algorithm>
> +



> +
> +static void
> +riscv_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *kindptr)
> +{
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +
> +  riscv_breakpoint_from_pc (gdbarch, pcptr, kindptr);
> +}
> +

remote_breakpoint_from_pc is removed in my patches
https://sourceware.org/ml/gdb-patches/2016-11/msg00031.html
They are not committed yet.  It would be good if you can rebase your
patches on top of mine when my patches are committed.

> +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)

Code style issue, only one space is needed between "int" and "regnum".
Many instances of such problem around your patch.

> +{
> +  int i;
> +  static char buf[20];
> +
> +  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
> +    return tdesc_register_name (gdbarch, regnum);

I don't think riscv port has target description yet.



> +
> +static void
> +riscv_extract_return_value (struct type *type,
> +			    struct regcache *regs,
> +			    gdb_byte *dst,
> +			    int regnum)

You need some comments on this function.

> +{
> +  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);
> +  ULONGEST tmp;
> +
> +  gdb_assert (len <= 2 * regsize);
> +
> +  while (len > 0)
> +    {
> +      regcache_cooked_read_unsigned (regs, regnum++, &tmp);
> +      store_unsigned_integer (valbuf, std::min (regsize, len), byte_order, tmp);

This line is too long.


> +      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.  */
> +

Nit: some lines are too long.

> +  /* 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 XXX gdbarch method.  */

> +static enum register_status
> +riscv_pseudo_register_read (struct gdbarch  *gdbarch,
> +			    struct regcache *regcache,
> +			    int              regnum,
> +			    gdb_byte        *buf)

Code style issue.

> +{
> +  return regcache_raw_read (regcache, regnum, buf);
> +}
> +

> +
> +static struct type *
> +riscv_register_type (struct gdbarch  *gdbarch,
> +		     int              regnum)
> +{
> +  int regsize = riscv_isa_regsize (gdbarch);
> +
> +  if (regnum < RISCV_FIRST_FP_REGNUM)
> +    {
> + int_regsizes:
> +      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);
> +	}
> +    }
> +  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;

return builtin_long_double in case regsize is 16?

> +	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;
> +
> +      goto int_regsizes;

goto is not necessarily needed.  Please remove it.

> +    }
> +}
> +
> +/* TODO: Replace all this with tdesc XML files.  */
> +static void
> +riscv_read_fp_register_single (struct frame_info *frame, int regno,
> +			       gdb_byte *rare_buffer)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (frame);
> +  int raw_size = register_size (gdbarch, regno);
> +  gdb_byte *raw_buffer = (gdb_byte *) alloca (raw_size);
> +
> +  if (!deprecated_frame_register_read (frame, regno, raw_buffer))

Use get_frame_register_value, your code can be simpler.

> +    error (_("can't read register %d (%s)"), regno,
> +	   gdbarch_register_name (gdbarch, regno));
> +
> +  if (raw_size == 8)
> +    {
> +      int offset;
> +
> +      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
> +	offset = 4;
> +      else
> +	offset = 0;
> +
> +      memcpy (rare_buffer, raw_buffer + offset, 4);
> +    }
> +  else
> +    memcpy (rare_buffer, raw_buffer, 4);
> +}
> +
> +static void
> +riscv_read_fp_register_double (struct frame_info *frame, int regno,
> +			       gdb_byte *rare_buffer)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (frame);
> +  int raw_size = register_size (gdbarch, regno);
> +
> +  if (raw_size == 8)
> +    {
> +      if (!deprecated_frame_register_read (frame, regno, rare_buffer))
> +	error (_("can't read register %d (%s)"), regno,
> +	       gdbarch_register_name (gdbarch, regno));
> +    }
> +  else
> +    internal_error (__FILE__, __LINE__,
> +		    _("%s: size says 32-bits, read is 64-bits."), __func__);
> +}
> +
> +static void
> +riscv_print_fp_register (struct ui_file *file, struct frame_info *frame,
> +			 int regnum)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (frame);
> +  gdb_byte *raw_buffer;
> +  struct value_print_options opts;
> +  double val;
> +  int inv;
> +  const char *regname;
> +
> +  raw_buffer = (gdb_byte *) alloca (2 * register_size (gdbarch, RISCV_FIRST_FP_REGNUM));
> +

This line is too long.

> +  fprintf_filtered (file, "%-15s", gdbarch_register_name (gdbarch, regnum));
> +
> +  if (register_size (gdbarch, regnum) == 4)
> +    {
> +      riscv_read_fp_register_single (frame, regnum, raw_buffer);
> +      val = unpack_double (builtin_type (gdbarch)->builtin_float, raw_buffer,
> +			   &inv);
> +
> +      get_formatted_print_options (&opts, 'x');
> +      print_scalar_formatted (raw_buffer,
> +			      builtin_type (gdbarch)->builtin_float,
> +			      &opts, 'w', file);
> +
> +      if (!inv)
> +	fprintf_filtered (file, "\t%-17.9g", val);
> +    }
> +  else
> +    {
> +      riscv_read_fp_register_double (frame, regnum, raw_buffer);
> +      val = unpack_double (builtin_type (gdbarch)->builtin_double, raw_buffer,
> +			   &inv);
> +
> +      get_formatted_print_options (&opts, 'x');
> +      print_scalar_formatted (raw_buffer,
> +			      builtin_type (gdbarch)->builtin_double,
> +			      &opts, 'g', file);
> +
> +      if (!inv)
> +	fprintf_filtered (file, "\t%-24.17g", val);
> +    }
> +
> +  if (inv)
> +    fprintf_filtered (file, "\t<invalid>");
> +}
> +




> +
> +static ULONGEST
> +riscv_fetch_instruction (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);

gdbarch_byte_order_for_code


> +
> +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 = -1;

IIRC, .addr's type is CORE_ADDR, which is unsigned.  Don't assign -1 to
a unsigned type.

> +}
> +
> +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)
> +    {
> +      unsigned long inst, opcode;
> +      int reg, rs1, imm12, rs2, offset12, funct3;
> +
> +      /* Fetch the instruction.  */
> +      inst = (unsigned long) riscv_fetch_instruction (gdbarch, cur_pc);

What if (unsigned long) is 4-bytes long, but riscv instruction is
8-bytes long?

> +      opcode = inst & 0x7F;
> +      reg = (inst >> 7) & 0x1F;
> +      rs1 = (inst >> 15) & 0x1F;
> +      imm12 = (inst >> 20) & 0xFFF;
> +      rs2 = (inst >> 20) & 0x1F;
> +      offset12 = (((inst >> 25) & 0x7F) << 5) + ((inst >> 7) & 0x1F);
> +      funct3 = (inst >> 12) & 0x7;
> +
> +      /* Look for common stack adjustment insns.  */
> +      if ((opcode == 0x13 || opcode == 0x1B) && reg == RISCV_SP_REGNUM
> +	  && rs1 == RISCV_SP_REGNUM)

Please use macros defined in include/opcode/riscv-opc.h, then the code
is much more readable.

> +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;
> +

code style issue,
https://www.gnu.org/prep/standards/standards.html#Formatting

int regnum = (TYPE_CODE (value_type) == TYPE_CODE_FLT
               ? RISCV_FA0_REGNUM : RISCV_A0_REGNUM);


> +
> +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;
> +  switch (abi)
> +    {
> +    case RISCV_ABI_FLAG_RV32I:
> +      tdep->register_size = 4;
> +      break;
> +    case RISCV_ABI_FLAG_RV64I:
> +      tdep->register_size = 8;

Since you've already had riscv_abi field in tdep, you can determine the
registers size on the fly.  Then, field register_size is not necessary
to me.

> +
> +  /* Information about the target architecture.  */
> +  set_gdbarch_return_value (gdbarch, riscv_return_value);
> +  set_gdbarch_breakpoint_from_pc (gdbarch, riscv_breakpoint_from_pc);

breakpoint_from_pc will be replaced by two new gdbarch methods, added in
my patches https://sourceware.org/ml/gdb-patches/2016-11/msg00031.html

> +  set_gdbarch_remote_breakpoint_from_pc (gdbarch, riscv_remote_breakpoint_from_pc);


> +
> +  /* Check any target description for validity.  */
> +  if (tdesc_has_registers (info.target_desc))
> +    {

We don't have riscv target description yet.

> +      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;
> +}
> +

> diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
> new file mode 100644
> index 0000000..ef10209
> --- /dev/null
> +++ b/gdb/riscv-tdep.h
> @@ -0,0 +1,101 @@
> +/* 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_RV32E	(0x10000000)	/* 32-bit Embedded Integer GPRs.  */
> +#define RISCV_ABI_FLAG_RV64I	(0x40000000)	/* 64-bit Integer GPRs.  */
> +#define RISCV_ABI_FLAG_RV128I	(0x80000000)	/* 128-bit Integer GPRs.  */
> +#define RISCV_ABI_FLAG_A	(1 << 0)	/* Atomics.  */
> +#define RISCV_ABI_FLAG_B	(1 << 1)	/* Bit Manipulation.  */
> +#define RISCV_ABI_FLAG_C	(1 << 2)	/* 16-bit Compressed Instructions.  */
> +#define RISCV_ABI_FLAG_D	(1 << 3)	/* Double-Precision Floating-Point.  */
> +#define RISCV_ABI_FLAG_E	(1 << 4)	/* Embedded base.  */
> +#define RISCV_ABI_FLAG_F	(1 << 5)	/* Single-Precision Floating-Point.  */
> +#define RISCV_ABI_FLAG_H	(1 << 7)	/* Hypervisor mode.  */
> +#define RISCV_ABI_FLAG_I	(1 << 8)	/* Base integer.  */
> +#define RISCV_ABI_FLAG_L	(1 << 11)	/* Decimal Floating-Point.  */
> +#define RISCV_ABI_FLAG_M	(1 << 12)	/* Integer Multiply and Division.  */
> +#define RISCV_ABI_FLAG_P	(1 << 15)	/* Packed-SIMD Extensions.  */
> +#define RISCV_ABI_FLAG_Q	(1 << 16)	/* Quad-Precision Floating-Point.  */
> +#define RISCV_ABI_FLAG_S	(1 << 18)	/* Supervisor mode.  */
> +#define RISCV_ABI_FLAG_T	(1 << 19)	/* Transactional Memory.  */
> +#define RISCV_ABI_FLAG_U	(1 << 20)	/* User mode.  */

I don't find where are they used.  Let us add them when they are really
used somewhere in the code.

> +
> +#define IS_RV32I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV32I)
> +#define IS_RV64I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV64I)
> +#define IS_RV128I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV128I)
> +
> +#define HAS_FPU(x)	((x) & (RISCV_ABI_FLAG_D | RISCV_ABI_FLAG_F))
> +

> +#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 {

I don't see how is this header file related to this patch?  Probably
this should be moved to sim patch.
  
Palmer Dabbelt Nov. 14, 2016, 10:39 p.m. UTC | #2
Sorry for taking a while to respond to this, we got a bit distracted by other
parts of the binutils port upstreaming process.

On Thu, 03 Nov 2016 05:38:53 PDT (-0700), qiyaoltc@gmail.com wrote:
> Palmer Dabbelt <palmer@dabbelt.com> writes:
>
> Hi Palmer,
> you need a ChangeLog entry, and a news entry for this new gdb port.
> There are some code style issues, please look at
> https://sourceware.org/gdb/wiki/ContributionChecklist
>
>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>> index 2c88434..e4e497b 100644
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>> @@ -691,7 +691,7 @@ ALL_TARGET_OBS = \
>>  	nios2-tdep.o nios2-linux-tdep.o \
>>  	nto-tdep.o \
>>  	ppc-linux-tdep.o ppcfbsd-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o  \
>> -	ppc-sysv-tdep.o ppc64-tdep.o rl78-tdep.o \
>> +	ppc-sysv-tdep.o ppc64-tdep.o riscv-tdep.o rl78-tdep.o \
>
> Miss riscv-linux-tdep.o?

  https://github.com/riscv/riscv-binutils-gdb/commit/76e33b6883db0e2a21b5fa460e7d2952f5760c08

>
>>  	rs6000-aix-tdep.o rs6000-tdep.o solib-aix.o ppc-ravenscar-thread.o \
>>  	rs6000-lynx178-tdep.o \
>>  	rx-tdep.o \
>> @@ -946,7 +946,7 @@ sparc64-tdep.h ppcobsd-tdep.h \
>>  coff-pe-read.h parser-defs.h gdb_ptrace.h mips-linux-tdep.h \
>>  m68k-tdep.h spu-tdep.h environ.h amd64-tdep.h \
>>  doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h ppc64-tdep.h \
>> -rs6000-tdep.h rs6000-aix-tdep.h \
>> +riscv-tdep.h rs6000-tdep.h rs6000-aix-tdep.h \
>>  common/gdb_locale.h arch-utils.h trad-frame.h gnu-nat.h \
>>  language.h nbsd-tdep.h solib-svr4.h \
>>  macroexp.h ui-file.h regcache.h tracepoint.h tracefile.h i386-tdep.h \
>> @@ -1734,6 +1734,7 @@ ALLDEPFILES = \
>>  	ravenscar-thread.c \
>>  	remote-sim.c \
>>  	dcache.c \
>> +	riscv-tdep.c \
>
> Miss riscv-linux-tdep.c?

  https://github.com/riscv/riscv-binutils-gdb/commit/76e33b6883db0e2a21b5fa460e7d2952f5760c08

>>  	rl78-tdep.c \
>>  	rs6000-nat.c rs6000-tdep.c solib-aix.c ppc-ravenscar-thread.c \
>>  	rs6000-lynx178-tdep.c \
>> diff --git a/gdb/config/riscv/linux.mh b/gdb/config/riscv/linux.mh
>> new file mode 100644
>> index 0000000..f68f371
>> --- /dev/null
>> +++ b/gdb/config/riscv/linux.mh
>> @@ -0,0 +1,30 @@
>> +#  Host: RISC-V based machine running GNU/Linux
>> +#
>> +#  Copyright (C) 2015 Free Software Foundation, Inc.
>
> 2016

  https://github.com/riscv/riscv-binutils-gdb/commit/7f008660df2b4859b80f1e7f8a29257ba831423d

>
>> +#  Contributed by Albert Ou <albert@sifive.com>.
>> +#
>
> Albert Ou doesn't have FSF copyright assignment.

Sorry about that, we got his paperwork all sorted out.

>> --- a/gdb/configure.ac
>> +++ b/gdb/configure.ac
>> @@ -515,6 +515,9 @@ esac
>>  # We might need to link with -lm; most simulators need it.
>>  AC_CHECK_LIB(m, main)
>>
>> +# The RISC-V simulator needs clock_gettime()
>> +AC_SEARCH_LIBS([clock_gettime], [rt])
>> +
>
> I don't know much in sim configure, but this is about sim, so I think
> this should be moved to sim/riscv/configure.ac.

I agree, but I couldn't make that work when I initially tried to implement this
(something about SIM_EXTRA_LIBS not getting passed far enough around).
Luckily, we've actually removed the dependency of our simulatior on
clock_gettime, so this can just be removed entirely.

  https://github.com/riscv/riscv-binutils-gdb/commit/f64950f9d68068acf1236f1ee9dd36eebc7b807e

>> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
>> index 8e34b7e..4457304 100644
>> --- a/gdb/infcmd.c
>> +++ b/gdb/infcmd.c
>> @@ -3447,8 +3447,9 @@ otherwise all the threads in the program are stopped.  To \n\
>>  interrupt all running threads in non-stop mode, use the -a option."));
>>
>>    c = add_info ("registers", nofp_registers_info, _("\
>> -List of integer registers and their contents, for selected stack frame.\n\
>> -Register name as argument means describe only that register."));
>> +Display registers and their contents, for the selected stack frame.\n\
>> +Usage: info registers [all|register|register group] ...\n\
>> +By default, the general register group will be shown."));
>
> Please split this change out this patch.  Put it into a separated patch,
> and give the reason why do you change that.

Sorry, I can't figure out why that's there.  I'm going to assume I screwed up
merging something at some point and drop the diff.

  https://github.com/riscv/riscv-binutils-gdb/commit/4ee773ddb3334393e0912c21db660a5d4a6f0ba4

Thanks for noticing!

>> diff --git a/gdb/riscv-linux-tdep.c b/gdb/riscv-linux-tdep.c
>> new file mode 100644
>> index 0000000..b66860c
>> --- /dev/null
>> +++ b/gdb/riscv-linux-tdep.c
>> @@ -0,0 +1,83 @@
>> +/* 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
>> +};
>> +
>
> All gdbarch methods are should be documented like this,
>
> /* Implement the iterate_over_regset_sections gdbarch method.  */
>
>> +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.  */
>> +  /* FIXME: This '0' should actually be a check to see if we're on
>> +     rv32, but I can't figure out how to hook that up (it's in
>> +     gdbarch_tdep, which we don't have here). */
>> +  set_solib_svr4_fetch_link_map_offsets
>> +    (gdbarch, (0) ?
>> +      svr4_ilp32_fetch_link_map_offsets :
>> +      svr4_lp64_fetch_link_map_offsets);
>
> gdbarch_tdep (gdbarch)->riscv_abi can tell you rv32 or rv64 is used.

OK, thanks!  At some point there was a merge that dropped the old way of doing
it and I couldn't figure out how to do it right.  Thanks for noticing!

  https://github.com/riscv/riscv-binutils-gdb/commit/0a9a29028cd26da628883bb49c0d5d06abaa30f4

>> --- /dev/null
>> +++ b/gdb/riscv-tdep.c
>> @@ -0,0 +1,1292 @@
>> +/* 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>.
>
> I don't find Todd Snyder's FSF copyright assignment.

OK, we'll try to sort this out.  One of the other bluespec guys has this filled
out, so I don't think it'll be a big headache.  I must have just missed a
contributer.  Thanks for finding him!

>> +
>> +   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 "opcode/riscv-opc.h"
>> +#include <algorithm>
>> +
>
>
>
>> +
>> +static void
>> +riscv_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *kindptr)
>> +{
>> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
>> +
>> +  riscv_breakpoint_from_pc (gdbarch, pcptr, kindptr);
>> +}
>> +
>
> remote_breakpoint_from_pc is removed in my patches
> https://sourceware.org/ml/gdb-patches/2016-11/msg00031.html
> They are not committed yet.  It would be good if you can rebase your
> patches on top of mine when my patches are committed.

I'll rebase every patchset I submit on top of the latest master, but this
specific issue has already been fixed.  Thanks for the heads up!

>> +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)
>
> Code style issue, only one space is needed between "int" and "regnum".
> Many instances of such problem around your patch.

I went through and fixed those issues.  There was also a large style-fix commit
that went through, hopefully it's all OK now.

  https://github.com/riscv/riscv-binutils-gdb/commit/ad8325bd484c1b2d0eb27ab403b1e87d69dd594e

>> +{
>> +  int i;
>> +  static char buf[20];
>> +
>> +  if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
>> +    return tdesc_register_name (gdbarch, regnum);
>
> I don't think riscv port has target description yet.

I'm not sure what a "target description" is.  Are you talking about this

  https://sourceware.org/gdb/onlinedocs/gdb/Target-Description-Format.html

?  If so then I don't think we have one, but I also can't figure out where
anyone else's is.

  riscv-binutils-gdb $ find -iname "*.dtd"
  ./gdb/features/threads.dtd
  ./gdb/features/btrace.dtd
  ./gdb/features/library-list.dtd
  ./gdb/features/osdata.dtd
  ./gdb/features/traceframe-info.dtd
  ./gdb/features/xinclude.dtd
  ./gdb/features/gdb-target.dtd
  ./gdb/features/library-list-svr4.dtd
  ./gdb/features/btrace-conf.dtd
  ./gdb/features/library-list-aix.dtd
  ./gdb/syscalls/gdb-syscalls.dtd
  riscv-binutils-gdb $ find -iname "*.dtd" | xargs grep 86

I feel like I must be missing something here.  Sorry!

>> +
>> +static void
>> +riscv_extract_return_value (struct type *type,
>> +			    struct regcache *regs,
>> +			    gdb_byte *dst,
>> +			    int regnum)
>
> You need some comments on this function.
>
>> +{
>> +  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);
>> +  ULONGEST tmp;
>> +
>> +  gdb_assert (len <= 2 * regsize);
>> +
>> +  while (len > 0)
>> +    {
>> +      regcache_cooked_read_unsigned (regs, regnum++, &tmp);
>> +      store_unsigned_integer (valbuf, std::min (regsize, len), byte_order, tmp);
>
> This line is too long.

Both fixed: https://github.com/riscv/riscv-binutils-gdb/commit/f75a58ffd7450915ee776594baceb95a0e10af99

>
>> +      len -= regsize;
>> +      valbuf += regsize;
>> +    }
>> +}
>> +
>
> /* Implement the return_value gdbarch method.  */

I'm not sure what you mean by this.

>> +
>> +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.  */
>> +
>
> Nit: some lines are too long.

I think it was only one

  https://github.com/riscv/riscv-binutils-gdb/commit/875e1bbf5b783d4b6b23786e73a89623fd4dadaa

>
>> +  /* 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 XXX gdbarch method.  */

I'm afraid I'm not sure what you're trying to say here, sorry!

>> +{
>> +  return regcache_raw_read (regcache, regnum, buf);
>> +}
>> +
>
>> +
>> +static struct type *
>> +riscv_register_type (struct gdbarch  *gdbarch,
>> +		     int              regnum)
>> +{
>> +  int regsize = riscv_isa_regsize (gdbarch);
>> +
>> +  if (regnum < RISCV_FIRST_FP_REGNUM)
>> +    {
>> + int_regsizes:
>> +      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);
>> +	}
>> +    }
>> +  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;
>
> return builtin_long_double in case regsize is 16?

I think this is actually correct as of right now -- we landed upstream a bit
quickly into binutils and one of the things that was still broken was that
"long double" was 64-bit on RISC-V.  Patches to fix this are part of the next
set I'm going to send to binutils, I'll fix this as well when they get
submitted.

>
>> +	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;
>> +
>> +      goto int_regsizes;
>
> goto is not necessarily needed.  Please remove it.

  https://github.com/riscv/riscv-binutils-gdb/commit/b8cfc4293684c3dcaa39fbcd68c75cb486452c00

>
>> +    }
>> +}
>> +
>> +/* TODO: Replace all this with tdesc XML files.  */
>> +static void
>> +riscv_read_fp_register_single (struct frame_info *frame, int regno,
>> +			       gdb_byte *rare_buffer)
>> +{
>> +  struct gdbarch *gdbarch = get_frame_arch (frame);
>> +  int raw_size = register_size (gdbarch, regno);
>> +  gdb_byte *raw_buffer = (gdb_byte *) alloca (raw_size);
>> +
>> +  if (!deprecated_frame_register_read (frame, regno, raw_buffer))
>
> Use get_frame_register_value, your code can be simpler.

MIPS (where this code came from) still uses the deprecated function.  I can't
figure out why this was deprecated or why MIPS is still using the old version,
and since this code does dangerous looking things (silently copying half of a
double-precision float) I'm not really sure how to change it.

>> +    error (_("can't read register %d (%s)"), regno,
>> +	   gdbarch_register_name (gdbarch, regno));
>> +
>> +  if (raw_size == 8)
>> +    {
>> +      int offset;
>> +
>> +      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
>> +	offset = 4;
>> +      else
>> +	offset = 0;
>> +
>> +      memcpy (rare_buffer, raw_buffer + offset, 4);
>> +    }
>> +  else
>> +    memcpy (rare_buffer, raw_buffer, 4);
>> +}
>> +
>> +static void
>> +riscv_read_fp_register_double (struct frame_info *frame, int regno,
>> +			       gdb_byte *rare_buffer)
>> +{
>> +  struct gdbarch *gdbarch = get_frame_arch (frame);
>> +  int raw_size = register_size (gdbarch, regno);
>> +
>> +  if (raw_size == 8)
>> +    {
>> +      if (!deprecated_frame_register_read (frame, regno, rare_buffer))
>> +	error (_("can't read register %d (%s)"), regno,
>> +	       gdbarch_register_name (gdbarch, regno));
>> +    }
>> +  else
>> +    internal_error (__FILE__, __LINE__,
>> +		    _("%s: size says 32-bits, read is 64-bits."), __func__);
>> +}
>> +
>> +static void
>> +riscv_print_fp_register (struct ui_file *file, struct frame_info *frame,
>> +			 int regnum)
>> +{
>> +  struct gdbarch *gdbarch = get_frame_arch (frame);
>> +  gdb_byte *raw_buffer;
>> +  struct value_print_options opts;
>> +  double val;
>> +  int inv;
>> +  const char *regname;
>> +
>> +  raw_buffer = (gdb_byte *) alloca (2 * register_size (gdbarch, RISCV_FIRST_FP_REGNUM));
>> +
>
> This line is too long.
>
>> +  fprintf_filtered (file, "%-15s", gdbarch_register_name (gdbarch, regnum));
>> +
>> +  if (register_size (gdbarch, regnum) == 4)
>> +    {
>> +      riscv_read_fp_register_single (frame, regnum, raw_buffer);
>> +      val = unpack_double (builtin_type (gdbarch)->builtin_float, raw_buffer,
>> +			   &inv);
>> +
>> +      get_formatted_print_options (&opts, 'x');
>> +      print_scalar_formatted (raw_buffer,
>> +			      builtin_type (gdbarch)->builtin_float,
>> +			      &opts, 'w', file);
>> +
>> +      if (!inv)
>> +	fprintf_filtered (file, "\t%-17.9g", val);
>> +    }
>> +  else
>> +    {
>> +      riscv_read_fp_register_double (frame, regnum, raw_buffer);
>> +      val = unpack_double (builtin_type (gdbarch)->builtin_double, raw_buffer,
>> +			   &inv);
>> +
>> +      get_formatted_print_options (&opts, 'x');
>> +      print_scalar_formatted (raw_buffer,
>> +			      builtin_type (gdbarch)->builtin_double,
>> +			      &opts, 'g', file);
>> +
>> +      if (!inv)
>> +	fprintf_filtered (file, "\t%-24.17g", val);
>> +    }
>> +
>> +  if (inv)
>> +    fprintf_filtered (file, "\t<invalid>");
>> +}
>> +
>
>
>
>
>> +
>> +static ULONGEST
>> +riscv_fetch_instruction (struct gdbarch *gdbarch, CORE_ADDR addr)
>> +{
>> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
>
> gdbarch_byte_order_for_code

Ah, thanks -- this would have been a pain to fix :)

  https://github.com/riscv/riscv-binutils-gdb/commit/f0ded1266c58a364481c8de57a884f8ac2d173a0

>> +
>> +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 = -1;
>
> IIRC, .addr's type is CORE_ADDR, which is unsigned.  Don't assign -1 to
> a unsigned type.

It looks like this is another one we got from MIPS.  I'm OK changing it, but
I'm not sure what the implications are.  I think 0 is the sanest value to put
in there?

  https://github.com/riscv/riscv-binutils-gdb/commit/73656f235a8b7cedaab10ee49bbc55dbf02e86ce

If that looks OK to you then I can go try to figure out if it's the right thing
to do.

>> +}
>> +
>> +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)
>> +    {
>> +      unsigned long inst, opcode;
>> +      int reg, rs1, imm12, rs2, offset12, funct3;
>> +
>> +      /* Fetch the instruction.  */
>> +      inst = (unsigned long) riscv_fetch_instruction (gdbarch, cur_pc);
>
> What if (unsigned long) is 4-bytes long, but riscv instruction is
> 8-bytes long?

We don't currently have any RISC-V instructions that are longer than 4 bytes.
The standard allows for this, but it doesn't look like there'll be any in the
near future.  I fixed it anyway, because the old version was uglier

  https://github.com/riscv/riscv-binutils-gdb/commit/34a6a4b4f553171d55de955ce75346ee781b6b2a

>> +      opcode = inst & 0x7F;
>> +      reg = (inst >> 7) & 0x1F;
>> +      rs1 = (inst >> 15) & 0x1F;
>> +      imm12 = (inst >> 20) & 0xFFF;
>> +      rs2 = (inst >> 20) & 0x1F;
>> +      offset12 = (((inst >> 25) & 0x7F) << 5) + ((inst >> 7) & 0x1F);
>> +      funct3 = (inst >> 12) & 0x7;
>> +
>> +      /* Look for common stack adjustment insns.  */
>> +      if ((opcode == 0x13 || opcode == 0x1B) && reg == RISCV_SP_REGNUM
>> +	  && rs1 == RISCV_SP_REGNUM)
>
> Please use macros defined in include/opcode/riscv-opc.h, then the code
> is much more readable.

I agree.  Whoever wrote this code must have either not known about riscv-opc.h,
or not liked those macros.  I added a FIXME for now

  https://github.com/riscv/riscv-binutils-gdb/commit/1b58570b0310850290ed5355776e78192e893d71

>> +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;
>> +
>
> code style issue,
> https://www.gnu.org/prep/standards/standards.html#Formatting
>
> int regnum = (TYPE_CODE (value_type) == TYPE_CODE_FLT
>                ? RISCV_FA0_REGNUM : RISCV_A0_REGNUM);
>

I think there were two formatting issues (one line was 80 characters)

  https://github.com/riscv/riscv-binutils-gdb/commit/c24e88a3e4464c922a669f84c1c67a1ae84444a1

>> +
>> +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;
>> +  switch (abi)
>> +    {
>> +    case RISCV_ABI_FLAG_RV32I:
>> +      tdep->register_size = 4;
>> +      break;
>> +    case RISCV_ABI_FLAG_RV64I:
>> +      tdep->register_size = 8;
>
> Since you've already had riscv_abi field in tdep, you can determine the
> registers size on the fly.  Then, field register_size is not necessary
> to me.

Sounds good to me.

  https://github.com/riscv/riscv-binutils-gdb/commit/09a286c89cdeea2c5ee21d239250a06bb3d92bc8

>> +
>> +  /* Information about the target architecture.  */
>> +  set_gdbarch_return_value (gdbarch, riscv_return_value);
>> +  set_gdbarch_breakpoint_from_pc (gdbarch, riscv_breakpoint_from_pc);
>
> breakpoint_from_pc will be replaced by two new gdbarch methods, added in
> my patches https://sourceware.org/ml/gdb-patches/2016-11/msg00031.html
>
>> +  set_gdbarch_remote_breakpoint_from_pc (gdbarch, riscv_remote_breakpoint_from_pc);

OK, thanks for the heads up.  I'll be sure to handle this when I rebase on top
of those, I don't think they've made it in yet.

>> +
>> +  /* Check any target description for validity.  */
>> +  if (tdesc_has_registers (info.target_desc))
>> +    {
>
> We don't have riscv target description yet.

Yes.  I'm amenable to adding one, but I'm not sure how.

>> +      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;
>> +}
>> +
>
>> diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
>> new file mode 100644
>> index 0000000..ef10209
>> --- /dev/null
>> +++ b/gdb/riscv-tdep.h
>> @@ -0,0 +1,101 @@
>> +/* 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_RV32E	(0x10000000)	/* 32-bit Embedded Integer GPRs.  */
>> +#define RISCV_ABI_FLAG_RV64I	(0x40000000)	/* 64-bit Integer GPRs.  */
>> +#define RISCV_ABI_FLAG_RV128I	(0x80000000)	/* 128-bit Integer GPRs.  */
>> +#define RISCV_ABI_FLAG_A	(1 << 0)	/* Atomics.  */
>> +#define RISCV_ABI_FLAG_B	(1 << 1)	/* Bit Manipulation.  */
>> +#define RISCV_ABI_FLAG_C	(1 << 2)	/* 16-bit Compressed Instructions.  */
>> +#define RISCV_ABI_FLAG_D	(1 << 3)	/* Double-Precision Floating-Point.  */
>> +#define RISCV_ABI_FLAG_E	(1 << 4)	/* Embedded base.  */
>> +#define RISCV_ABI_FLAG_F	(1 << 5)	/* Single-Precision Floating-Point.  */
>> +#define RISCV_ABI_FLAG_H	(1 << 7)	/* Hypervisor mode.  */
>> +#define RISCV_ABI_FLAG_I	(1 << 8)	/* Base integer.  */
>> +#define RISCV_ABI_FLAG_L	(1 << 11)	/* Decimal Floating-Point.  */
>> +#define RISCV_ABI_FLAG_M	(1 << 12)	/* Integer Multiply and Division.  */
>> +#define RISCV_ABI_FLAG_P	(1 << 15)	/* Packed-SIMD Extensions.  */
>> +#define RISCV_ABI_FLAG_Q	(1 << 16)	/* Quad-Precision Floating-Point.  */
>> +#define RISCV_ABI_FLAG_S	(1 << 18)	/* Supervisor mode.  */
>> +#define RISCV_ABI_FLAG_T	(1 << 19)	/* Transactional Memory.  */
>> +#define RISCV_ABI_FLAG_U	(1 << 20)	/* User mode.  */
>
> I don't find where are they used.  Let us add them when they are really
> used somewhere in the code.

Sounds good to me.

  https://github.com/riscv/riscv-binutils-gdb/commit/69e45cdcc667371ce60db88ae613709e6f37dcce

>> +
>> +#define IS_RV32I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV32I)
>> +#define IS_RV64I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV64I)
>> +#define IS_RV128I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV128I)
>> +
>> +#define HAS_FPU(x)	((x) & (RISCV_ABI_FLAG_D | RISCV_ABI_FLAG_F))
>> +
>
>> +#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 {
>
> I don't see how is this header file related to this patch?  Probably
> this should be moved to sim patch.

Yes, I must have added it by mistake.

Thanks for all the feedback.  I'll incorporate all this into a v2, which will
be rebased onto the latest binutils-gdb master.
  
Pedro Alves Nov. 16, 2016, 7:36 p.m. UTC | #3
On 11/14/2016 10:39 PM, Palmer Dabbelt wrote:
>>> >> +
>>> >> +  /* Check any target description for validity.  */
>>> >> +  if (tdesc_has_registers (info.target_desc))
>>> >> +    {
>> >
>> > We don't have riscv target description yet.
> Yes.  I'm amenable to adding one, but I'm not sure how.
> 

You should really add them.  Take a look at the ARC port,
which was recently added:

  https://sourceware.org/ml/gdb-patches/2016-09/msg00248.html

Thanks,
Pedro Alves
  
Palmer Dabbelt Nov. 16, 2016, 7:40 p.m. UTC | #4
On Wed, 16 Nov 2016 11:36:29 PST (-0800), palves@redhat.com wrote:
> On 11/14/2016 10:39 PM, Palmer Dabbelt wrote:
>>>> >> +
>>>> >> +  /* Check any target description for validity.  */
>>>> >> +  if (tdesc_has_registers (info.target_desc))
>>>> >> +    {
>>> >
>>> > We don't have riscv target description yet.
>> Yes.  I'm amenable to adding one, but I'm not sure how.
>>
>
> You should really add them.  Take a look at the ARC port,
> which was recently added:
>
>   https://sourceware.org/ml/gdb-patches/2016-09/msg00248.html

Great, thanks -- I was looking for .dtd files, not .xml files.  From looking at
their port, it looks like I want to add a

  gdb/features/riscv.xml

patterned off of

  gdb/features/arc-v2.xml

It looks like there's a whole bunch of examples in there, so if I'm on the
right track I can probably figure it out.
  
Pedro Alves Nov. 16, 2016, 7:48 p.m. UTC | #5
On 11/16/2016 07:40 PM, Palmer Dabbelt wrote:
> On Wed, 16 Nov 2016 11:36:29 PST (-0800), palves@redhat.com wrote:
>> On 11/14/2016 10:39 PM, Palmer Dabbelt wrote:
>>>>>>> +
>>>>>>> +  /* Check any target description for validity.  */
>>>>>>> +  if (tdesc_has_registers (info.target_desc))
>>>>>>> +    {
>>>>>
>>>>> We don't have riscv target description yet.
>>> Yes.  I'm amenable to adding one, but I'm not sure how.
>>>
>>
>> You should really add them.  Take a look at the ARC port,
>> which was recently added:
>>
>>   https://sourceware.org/ml/gdb-patches/2016-09/msg00248.html
> 
> Great, thanks -- I was looking for .dtd files, not .xml files.  

dtd files are standard xml Document Type Definition files.
The dtd file in question is features/gdb-target.dtd.  
I.e., the xml file you'll write follows that dtd.

> From looking at
> their port, it looks like I want to add a
> 
>   gdb/features/riscv.xml

Yup.

> 
> patterned off of
> 
>   gdb/features/arc-v2.xml
> 
> It looks like there's a whole bunch of examples in there, so if I'm on the
> right track I can probably figure it out.

See here too:

 https://sourceware.org/gdb/onlinedocs/gdb/Target-Description-Format.html

FYI, with target descriptions, the remote stub send a target description
that includes whatever custom registers the chip has, and gdb will
include them in "info registers", etc. all without any gdb modification.

Thanks,
Pedro Alves
  
Yao Qi Nov. 16, 2016, 9:39 p.m. UTC | #6
On Mon, Nov 14, 2016 at 10:39 PM, Palmer Dabbelt <palmer@dabbelt.com> wrote:
>>
>> /* Implement the return_value gdbarch method.  */
>
> I'm not sure what you mean by this.
>

I suggested that such comment is needed to any gdbarch methods implemented
for riscv.  In this case, it is riscv_return_value.

>>> +
>>> +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)
>>

>> /* Implement the XXX gdbarch method.  */
>
> I'm afraid I'm not sure what you're trying to say here, sorry!
>

Likewise.  Such comments are needed.

>>> +{
>>> +  return regcache_raw_read (regcache, regnum, buf);
>>> +}
>>> +
>>
>>> +

>>> +static void
>>> +riscv_read_fp_register_single (struct frame_info *frame, int regno,
>>> +                           gdb_byte *rare_buffer)
>>> +{
>>> +  struct gdbarch *gdbarch = get_frame_arch (frame);
>>> +  int raw_size = register_size (gdbarch, regno);
>>> +  gdb_byte *raw_buffer = (gdb_byte *) alloca (raw_size);
>>> +
>>> +  if (!deprecated_frame_register_read (frame, regno, raw_buffer))
>>
>> Use get_frame_register_value, your code can be simpler.
>
> MIPS (where this code came from) still uses the deprecated function.  I can't
> figure out why this was deprecated or why MIPS is still using the old version,
> and since this code does dangerous looking things (silently copying half of a
> double-precision float) I'm not really sure how to change it.
>

riscv_read_fp_register_single is called for printing registers, so you can
use value and print it via val_print.  Then, riscv_read_fp_register_single can
be removed.  Just grep get_frame_register_value, and see how it is used
in other ports.

>>> +
>>> +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 = -1;
>>
>> IIRC, .addr's type is CORE_ADDR, which is unsigned.  Don't assign -1 to
>> a unsigned type.
>
> It looks like this is another one we got from MIPS.  I'm OK changing it, but
> I'm not sure what the implications are.  I think 0 is the sanest value to put
> in there?
>
>   https://github.com/riscv/riscv-binutils-gdb/commit/73656f235a8b7cedaab10ee49bbc55dbf02e86ce
>
> If that looks OK to you then I can go try to figure out if it's the right thing
> to do.
>

save_regs is a an array of struct trad_frame_saved_reg, and the type of
.addr is LONGEST, so it would be fine to set it to -1.  I withdraw my comments
on this.

>>> +      opcode = inst & 0x7F;
>>> +      reg = (inst >> 7) & 0x1F;
>>> +      rs1 = (inst >> 15) & 0x1F;
>>> +      imm12 = (inst >> 20) & 0xFFF;
>>> +      rs2 = (inst >> 20) & 0x1F;
>>> +      offset12 = (((inst >> 25) & 0x7F) << 5) + ((inst >> 7) & 0x1F);
>>> +      funct3 = (inst >> 12) & 0x7;
>>> +
>>> +      /* Look for common stack adjustment insns.  */
>>> +      if ((opcode == 0x13 || opcode == 0x1B) && reg == RISCV_SP_REGNUM
>>> +      && rs1 == RISCV_SP_REGNUM)
>>
>> Please use macros defined in include/opcode/riscv-opc.h, then the code
>> is much more readable.
>
> I agree.  Whoever wrote this code must have either not known about riscv-opc.h,
> or not liked those macros.  I added a FIXME for now
>
>   https://github.com/riscv/riscv-binutils-gdb/commit/1b58570b0310850290ed5355776e78192e893d71
>

Well, FIXME is not enough :-)  Please replace these magic numbers with macro.
  

Patch

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2c88434..e4e497b 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -691,7 +691,7 @@  ALL_TARGET_OBS = \
 	nios2-tdep.o nios2-linux-tdep.o \
 	nto-tdep.o \
 	ppc-linux-tdep.o ppcfbsd-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o  \
-	ppc-sysv-tdep.o ppc64-tdep.o rl78-tdep.o \
+	ppc-sysv-tdep.o ppc64-tdep.o riscv-tdep.o rl78-tdep.o \
 	rs6000-aix-tdep.o rs6000-tdep.o solib-aix.o ppc-ravenscar-thread.o \
 	rs6000-lynx178-tdep.o \
 	rx-tdep.o \
@@ -946,7 +946,7 @@  sparc64-tdep.h ppcobsd-tdep.h \
 coff-pe-read.h parser-defs.h gdb_ptrace.h mips-linux-tdep.h \
 m68k-tdep.h spu-tdep.h environ.h amd64-tdep.h \
 doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h ppc64-tdep.h \
-rs6000-tdep.h rs6000-aix-tdep.h \
+riscv-tdep.h rs6000-tdep.h rs6000-aix-tdep.h \
 common/gdb_locale.h arch-utils.h trad-frame.h gnu-nat.h \
 language.h nbsd-tdep.h solib-svr4.h \
 macroexp.h ui-file.h regcache.h tracepoint.h tracefile.h i386-tdep.h \
@@ -1734,6 +1734,7 @@  ALLDEPFILES = \
 	ravenscar-thread.c \
 	remote-sim.c \
 	dcache.c \
+	riscv-tdep.c \
 	rl78-tdep.c \
 	rs6000-nat.c rs6000-tdep.c solib-aix.c ppc-ravenscar-thread.c \
 	rs6000-lynx178-tdep.c \
diff --git a/gdb/config/riscv/linux.mh b/gdb/config/riscv/linux.mh
new file mode 100644
index 0000000..f68f371
--- /dev/null
+++ b/gdb/config/riscv/linux.mh
@@ -0,0 +1,30 @@ 
+#  Host: RISC-V based machine running GNU/Linux
+#
+#  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/>.
+
+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/configure.ac b/gdb/configure.ac
index e451e60..2147e62 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -515,6 +515,9 @@  esac
 # We might need to link with -lm; most simulators need it.
 AC_CHECK_LIB(m, main)
 
+# The RISC-V simulator needs clock_gettime()
+AC_SEARCH_LIBS([clock_gettime], [rt])
+
 # We need to link with -lw to get `wctype' on Solaris before Solaris
 # 2.6.  Solaris 2.6 and beyond have this function in libc, and have a
 # libw that some versions of the GNU linker cannot hanle (GNU ld 2.9.1
diff --git a/gdb/configure.host b/gdb/configure.host
index ef265eb..d887f44 100644
--- a/gdb/configure.host
+++ b/gdb/configure.host
@@ -64,6 +64,7 @@  m68*)			gdb_host_cpu=m68k ;;
 m88*)			gdb_host_cpu=m88k ;;
 mips*)			gdb_host_cpu=mips ;;
 powerpc* | rs6000)	gdb_host_cpu=powerpc ;;
+riscv*)                 gdb_host_cpu=riscv ;;
 sparcv9 | sparc64)	gdb_host_cpu=sparc ;;
 s390*)			gdb_host_cpu=s390 ;;
 sh*)			gdb_host_cpu=sh ;;
@@ -147,6 +148,8 @@  powerpc64*-*-linux*)	gdb_host=ppc64-linux
 			;;
 powerpc*-*-linux*)	gdb_host=linux ;;
 
+riscv*-linux*)          gdb_host=linux ;;
+
 s390*-*-linux*)		gdb_host=linux ;;
 
 sh*-*-netbsdelf* | sh*-*-knetbsd*-gnu)
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index d428dff..2dce609 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -478,6 +478,18 @@  s390*-*-linux*)
 	build_gdbserver=yes
 	;;
 
+riscv*-*-linux*)
+	# Target Linux/RISC-V
+	gdb_target_obs="riscv-tdep.o riscv-linux-tdep.o \
+			glibc-tdep.o linux-tdep.o solib-svr4.o"
+	;;
+
+riscv*-*-*)
+	# Target: RISC-V architecture
+	gdb_target_obs="riscv-tdep.o"
+	gdb_sim=../sim/riscv/libsim.a
+	;;
+
 rl78-*-elf)
 	# Target: Renesas rl78
 	gdb_target_obs="rl78-tdep.o"
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 8e34b7e..4457304 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -3447,8 +3447,9 @@  otherwise all the threads in the program are stopped.  To \n\
 interrupt all running threads in non-stop mode, use the -a option."));
 
   c = add_info ("registers", nofp_registers_info, _("\
-List of integer registers and their contents, for selected stack frame.\n\
-Register name as argument means describe only that register."));
+Display registers and their contents, for the selected stack frame.\n\
+Usage: info registers [all|register|register group] ...\n\
+By default, the general register group will be shown."));
   add_info_alias ("r", "registers", 1);
   set_cmd_completer (c, reg_or_group_completer);
 
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..b66860c
--- /dev/null
+++ b/gdb/riscv-linux-tdep.c
@@ -0,0 +1,83 @@ 
+/* 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.  */
+  /* FIXME: This '0' should actually be a check to see if we're on
+     rv32, but I can't figure out how to hook that up (it's in
+     gdbarch_tdep, which we don't have here). */
+  set_solib_svr4_fetch_link_map_offsets
+    (gdbarch, (0) ?
+      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..9afd28d
--- /dev/null
+++ b/gdb/riscv-tdep.c
@@ -0,0 +1,1292 @@ 
+/* 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 "opcode/riscv-opc.h"
+#include <algorithm>
+
+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 const gdb_byte *
+riscv_breakpoint_from_pc (struct gdbarch *gdbarch,
+			  CORE_ADDR      *bp_addr,
+			  int            *bp_size)
+{
+  /* TODO: Support C.EBREAK for compressed (16-bit) insns.  */
+  /* TODO: Support NOPs for >=6 byte insns.  */
+  static const gdb_byte sbreak_insn[] = { 0x73, 0x00, 0x10, 0x00, };
+
+  *bp_size = 4;
+
+  return sbreak_insn;
+}
+
+static void
+riscv_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *kindptr)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  riscv_breakpoint_from_pc (gdbarch, pcptr, kindptr);
+}
+
+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;
+}
+
+static const char *
+riscv_register_name (struct gdbarch *gdbarch,
+		     int             regnum)
+{
+  return register_name(gdbarch, regnum, 0);
+}
+
+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);
+  ULONGEST tmp;
+
+  gdb_assert (len <= 2 * regsize);
+
+  while (len > 0)
+    {
+      regcache_cooked_read_unsigned (regs, regnum++, &tmp);
+      store_unsigned_integer (valbuf, std::min (regsize, 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;
+    }
+}
+
+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;
+}
+
+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);
+}
+
+static void
+riscv_pseudo_register_write (struct gdbarch  *gdbarch,
+			     struct regcache *regcache,
+			     int              cookednum,
+			     const gdb_byte  *buf)
+{
+  regcache_raw_write (regcache, cookednum, buf);
+}
+
+static struct type *
+riscv_register_type (struct gdbarch  *gdbarch,
+		     int              regnum)
+{
+  int regsize = riscv_isa_regsize (gdbarch);
+
+  if (regnum < RISCV_FIRST_FP_REGNUM)
+    {
+ int_regsizes:
+      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);
+	}
+    }
+  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;
+
+      goto int_regsizes;
+    }
+}
+
+/* TODO: Replace all this with tdesc XML files.  */
+static void
+riscv_read_fp_register_single (struct frame_info *frame, int regno,
+			       gdb_byte *rare_buffer)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int raw_size = register_size (gdbarch, regno);
+  gdb_byte *raw_buffer = (gdb_byte *) alloca (raw_size);
+
+  if (!deprecated_frame_register_read (frame, regno, raw_buffer))
+    error (_("can't read register %d (%s)"), regno,
+	   gdbarch_register_name (gdbarch, regno));
+
+  if (raw_size == 8)
+    {
+      int offset;
+
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+	offset = 4;
+      else
+	offset = 0;
+
+      memcpy (rare_buffer, raw_buffer + offset, 4);
+    }
+  else
+    memcpy (rare_buffer, raw_buffer, 4);
+}
+
+static void
+riscv_read_fp_register_double (struct frame_info *frame, int regno,
+			       gdb_byte *rare_buffer)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int raw_size = register_size (gdbarch, regno);
+
+  if (raw_size == 8)
+    {
+      if (!deprecated_frame_register_read (frame, regno, rare_buffer))
+	error (_("can't read register %d (%s)"), regno,
+	       gdbarch_register_name (gdbarch, regno));
+    }
+  else
+    internal_error (__FILE__, __LINE__,
+		    _("%s: size says 32-bits, read is 64-bits."), __func__);
+}
+
+static void
+riscv_print_fp_register (struct ui_file *file, struct frame_info *frame,
+			 int regnum)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  gdb_byte *raw_buffer;
+  struct value_print_options opts;
+  double val;
+  int inv;
+  const char *regname;
+
+  raw_buffer = (gdb_byte *) alloca (2 * register_size (gdbarch, RISCV_FIRST_FP_REGNUM));
+
+  fprintf_filtered (file, "%-15s", gdbarch_register_name (gdbarch, regnum));
+
+  if (register_size (gdbarch, regnum) == 4)
+    {
+      riscv_read_fp_register_single (frame, regnum, raw_buffer);
+      val = unpack_double (builtin_type (gdbarch)->builtin_float, raw_buffer,
+			   &inv);
+
+      get_formatted_print_options (&opts, 'x');
+      print_scalar_formatted (raw_buffer,
+			      builtin_type (gdbarch)->builtin_float,
+			      &opts, 'w', file);
+
+      if (!inv)
+	fprintf_filtered (file, "\t%-17.9g", val);
+    }
+  else
+    {
+      riscv_read_fp_register_double (frame, regnum, raw_buffer);
+      val = unpack_double (builtin_type (gdbarch)->builtin_double, raw_buffer,
+			   &inv);
+
+      get_formatted_print_options (&opts, 'x');
+      print_scalar_formatted (raw_buffer,
+			      builtin_type (gdbarch)->builtin_double,
+			      &opts, 'g', file);
+
+      if (!inv)
+	fprintf_filtered (file, "\t%-24.17g", val);
+    }
+
+  if (inv)
+    fprintf_filtered (file, "\t<invalid>");
+}
+
+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)
+	{
+	  d = unpack_long (builtin_type (gdbarch)->builtin_int32, raw_buffer);
+	  fprintf_filtered (file, "IP:%02X IM:%02X EA:%d VM:%d S64:%d U64:%d EF:%d PEI:%d EI:%d PS:%d S:%d",
+			    (int)((d >> 24) & 0xFF),
+			    (int)((d >> 16) & 0xFF),
+			    (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");
+}
+
+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"));
+}
+
+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 (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 = -1;
+}
+
+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)
+    {
+      unsigned long inst, opcode;
+      int reg, rs1, imm12, rs2, offset12, funct3;
+
+      /* Fetch the instruction.  */
+      inst = (unsigned long) riscv_fetch_instruction (gdbarch, cur_pc);
+      opcode = inst & 0x7F;
+      reg = (inst >> 7) & 0x1F;
+      rs1 = (inst >> 15) & 0x1F;
+      imm12 = (inst >> 20) & 0xFFF;
+      rs2 = (inst >> 20) & 0x1F;
+      offset12 = (((inst >> 25) & 0x7F) << 5) + ((inst >> 7) & 0x1F);
+      funct3 = (inst >> 12) & 0x7;
+
+      /* Look for common stack adjustment insns.  */
+      if ((opcode == 0x13 || opcode == 0x1B) && 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 (opcode == 0x23 && funct3 == 0x2 && rs1 == RISCV_SP_REGNUM)
+	{
+	  /* sw reg, offset(sp) */
+	  set_reg_offset (gdbarch, this_cache, rs1, sp + offset12);
+	}
+      else if (opcode == 0x23 && funct3 == 0x3 && rs1 == RISCV_SP_REGNUM)
+	{
+	  /* sd reg, offset(sp) */
+	  set_reg_offset (gdbarch, this_cache, rs1, sp + offset12);
+	}
+      else if (opcode == 0x13 && 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 ((opcode == 0x33 || opcode == 0x3B) && 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 (opcode == 0x23 && funct3 == 0x2 && rs1 == RISCV_FP_REGNUM)
+	{
+	  /* sw reg, offset(s0) */
+	  set_reg_offset (gdbarch, this_cache, rs1, frame_addr + offset12);
+	}
+      else if (reg == RISCV_GP_REGNUM
+	       && (opcode == 0x17 || opcode == 0x37
+		   || (opcode == 0x13 && rs1 == RISCV_GP_REGNUM)
+		   || (opcode == 0x33 && (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;
+}
+
+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, tdep->register_size, 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;
+}
+
+static CORE_ADDR
+riscv_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  return align_down (addr, 16);
+}
+
+static CORE_ADDR
+riscv_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, RISCV_PC_REGNUM);
+}
+
+static CORE_ADDR
+riscv_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, RISCV_SP_REGNUM);
+}
+
+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;
+  switch (abi)
+    {
+    case RISCV_ABI_FLAG_RV32I:
+      tdep->register_size = 4;
+      break;
+    case RISCV_ABI_FLAG_RV64I:
+      tdep->register_size = 8;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__, _("unknown abi %i"), abi);
+      tdep->register_size = 4;
+      break;
+    }
+
+  /* Target data types.  */
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 32);
+  set_gdbarch_long_bit (gdbarch, tdep->register_size * 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, tdep->register_size * 8);
+  set_gdbarch_char_signed (gdbarch, 1);
+
+  /* Information about the target architecture.  */
+  set_gdbarch_return_value (gdbarch, riscv_return_value);
+  set_gdbarch_breakpoint_from_pc (gdbarch, riscv_breakpoint_from_pc);
+  set_gdbarch_remote_breakpoint_from_pc (gdbarch, riscv_remote_breakpoint_from_pc);
+  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);
+}
diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
new file mode 100644
index 0000000..ef10209
--- /dev/null
+++ b/gdb/riscv-tdep.h
@@ -0,0 +1,101 @@ 
+/* 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_RV32E	(0x10000000)	/* 32-bit Embedded Integer GPRs.  */
+#define RISCV_ABI_FLAG_RV64I	(0x40000000)	/* 64-bit Integer GPRs.  */
+#define RISCV_ABI_FLAG_RV128I	(0x80000000)	/* 128-bit Integer GPRs.  */
+#define RISCV_ABI_FLAG_A	(1 << 0)	/* Atomics.  */
+#define RISCV_ABI_FLAG_B	(1 << 1)	/* Bit Manipulation.  */
+#define RISCV_ABI_FLAG_C	(1 << 2)	/* 16-bit Compressed Instructions.  */
+#define RISCV_ABI_FLAG_D	(1 << 3)	/* Double-Precision Floating-Point.  */
+#define RISCV_ABI_FLAG_E	(1 << 4)	/* Embedded base.  */
+#define RISCV_ABI_FLAG_F	(1 << 5)	/* Single-Precision Floating-Point.  */
+#define RISCV_ABI_FLAG_H	(1 << 7)	/* Hypervisor mode.  */
+#define RISCV_ABI_FLAG_I	(1 << 8)	/* Base integer.  */
+#define RISCV_ABI_FLAG_L	(1 << 11)	/* Decimal Floating-Point.  */
+#define RISCV_ABI_FLAG_M	(1 << 12)	/* Integer Multiply and Division.  */
+#define RISCV_ABI_FLAG_P	(1 << 15)	/* Packed-SIMD Extensions.  */
+#define RISCV_ABI_FLAG_Q	(1 << 16)	/* Quad-Precision Floating-Point.  */
+#define RISCV_ABI_FLAG_S	(1 << 18)	/* Supervisor mode.  */
+#define RISCV_ABI_FLAG_T	(1 << 19)	/* Transactional Memory.  */
+#define RISCV_ABI_FLAG_U	(1 << 20)	/* User mode.  */
+
+#define IS_RV32I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV32I)
+#define IS_RV64I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV64I)
+#define IS_RV128I(x)	(((x) & 0xF0000000) == RISCV_ABI_FLAG_RV128I)
+
+#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;
+  int register_size;
+};
+
+static inline int
+riscv_isa_regsize (struct gdbarch *gdbarch)
+{
+  return gdbarch_tdep (gdbarch)->register_size;
+}
+
+#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
+};