diff mbox

[v2,3/4] Add FreeBSD/riscv architecture.

Message ID 20180924205151.22217-4-jhb@FreeBSD.org
State New
Headers show

Commit Message

John Baldwin Sept. 24, 2018, 8:51 p.m. UTC
Support for collecting and supplying general purpose and floating
point register sets is provided along with signal frame unwinding.

FreeBSD only supports RV64 currently, so while some provision is made
for RV32 in the general-purpose register set, the changes have only
been tested on RV64.

gdb/ChangeLog:

	* Makefile.in (ALL_TARGET_OBS): Add riscv-fbsd-tdep.o.
	(HFILES_NO_SRCDIR): Add riscv-fbsd-tdep.h.
	(ALLDEPFILES): Add riscv-fbsd-tdep.c.
	* NEWS: Mention new FreeBSD/riscv target.
	* configure.tgt: Add riscv*-*-freebsd*.
	* riscv-fbsd-tdep.c: New file.
	* riscv-fbsd-tdep.h: New file.
---
 gdb/ChangeLog         |  10 ++
 gdb/Makefile.in       |   3 +
 gdb/NEWS              |   1 +
 gdb/configure.tgt     |   5 +
 gdb/riscv-fbsd-tdep.c | 206 ++++++++++++++++++++++++++++++++++++++++++
 gdb/riscv-fbsd-tdep.h |  33 +++++++
 6 files changed, 258 insertions(+)
 create mode 100644 gdb/riscv-fbsd-tdep.c
 create mode 100644 gdb/riscv-fbsd-tdep.h

Comments

Eli Zaretskii Sept. 24, 2018, 9:15 p.m. UTC | #1
> From: John Baldwin <jhb@FreeBSD.org>
> Cc: andrew.burgess@embecosm.com,	jimw@sifive.com
> Date: Mon, 24 Sep 2018 13:51:50 -0700
> 
> gdb/ChangeLog:
> 
> 	* Makefile.in (ALL_TARGET_OBS): Add riscv-fbsd-tdep.o.
> 	(HFILES_NO_SRCDIR): Add riscv-fbsd-tdep.h.
> 	(ALLDEPFILES): Add riscv-fbsd-tdep.c.
> 	* NEWS: Mention new FreeBSD/riscv target.
> 	* configure.tgt: Add riscv*-*-freebsd*.
> 	* riscv-fbsd-tdep.c: New file.
> 	* riscv-fbsd-tdep.h: New file.

OK for the NEWS part.

Thanks.
Simon Marchi Sept. 27, 2018, 7:59 p.m. UTC | #2
On 2018-09-24 04:51 PM, John Baldwin wrote:
> +/* Implement the "init" method of struct tramp_frame.  */

> +

> +static void

> +riscv_fbsd_sigframe_init (const struct tramp_frame *self,

> +			  struct frame_info *this_frame,

> +			  struct trad_frame_cache *this_cache,

> +			  CORE_ADDR func)

> +{

> +  struct gdbarch *gdbarch = get_frame_arch (this_frame);

> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);

> +  CORE_ADDR sp = get_frame_register_unsigned (this_frame, RISCV_SP_REGNUM);

> +  CORE_ADDR mcontext_addr =

> +    sp

> +    + RISCV_SIGFRAME_UCONTEXT_OFFSET

> +    + RISCV_UCONTEXT_MCONTEXT_OFFSET;


Just a formatting nit, to match the GNU style it should be something like

  CORE_ADDR mcontext_addr
    = (sp
       + RISCV_SIGFRAME_UCONTEXT_OFFSET
       + RISCV_UCONTEXT_MCONTEXT_OFFSET);

The break should always be before a binary operator, and the parentheses help (I've
been told) with auto-formatting in Emacs.

Otherwise everything looks good to me, but again I think the RISC-V wizards should take a look.

Simon
Andrew Burgess Sept. 28, 2018, 10:35 a.m. UTC | #3
* John Baldwin <jhb@FreeBSD.org> [2018-09-24 13:51:50 -0700]:

> Support for collecting and supplying general purpose and floating
> point register sets is provided along with signal frame unwinding.
> 
> FreeBSD only supports RV64 currently, so while some provision is made
> for RV32 in the general-purpose register set, the changes have only
> been tested on RV64.
> 
> gdb/ChangeLog:
> 
> 	* Makefile.in (ALL_TARGET_OBS): Add riscv-fbsd-tdep.o.
> 	(HFILES_NO_SRCDIR): Add riscv-fbsd-tdep.h.
> 	(ALLDEPFILES): Add riscv-fbsd-tdep.c.
> 	* NEWS: Mention new FreeBSD/riscv target.
> 	* configure.tgt: Add riscv*-*-freebsd*.
> 	* riscv-fbsd-tdep.c: New file.
> 	* riscv-fbsd-tdep.h: New file.

I haven't tested the code yet, but I took a look through and I'm happy
with this being merged (with Simon's nit fixed).

Thanks,
Andrew




> ---
>  gdb/ChangeLog         |  10 ++
>  gdb/Makefile.in       |   3 +
>  gdb/NEWS              |   1 +
>  gdb/configure.tgt     |   5 +
>  gdb/riscv-fbsd-tdep.c | 206 ++++++++++++++++++++++++++++++++++++++++++
>  gdb/riscv-fbsd-tdep.h |  33 +++++++
>  6 files changed, 258 insertions(+)
>  create mode 100644 gdb/riscv-fbsd-tdep.c
>  create mode 100644 gdb/riscv-fbsd-tdep.h
> 
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index f56b0487cc..1367f37db7 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,13 @@
> +2018-09-24  John Baldwin  <jhb@FreeBSD.org>
> +
> +	* Makefile.in (ALL_TARGET_OBS): Add riscv-fbsd-tdep.o.
> +	(HFILES_NO_SRCDIR): Add riscv-fbsd-tdep.h.
> +	(ALLDEPFILES): Add riscv-fbsd-tdep.c.
> +	* NEWS: Mention new FreeBSD/riscv target.
> +	* configure.tgt: Add riscv*-*-freebsd*.
> +	* riscv-fbsd-tdep.c: New file.
> +	* riscv-fbsd-tdep.h: New file.
> +
>  2018-09-24  John Baldwin  <jhb@FreeBSD.org>
>  
>  	* disasm-selftests.c (print_one_insn_test): Add bfd_arch_riscv to
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 3b158fa1db..2e03bb956c 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -745,6 +745,7 @@ ALL_TARGET_OBS = \
>  	ppc-sysv-tdep.o \
>  	ppc64-tdep.o \
>  	ravenscar-thread.o \
> +	riscv-fbsd-tdep.o \
>  	riscv-linux-tdep.o \
>  	riscv-tdep.o \
>  	rl78-tdep.o \
> @@ -1339,6 +1340,7 @@ HFILES_NO_SRCDIR = \
>  	remote.h \
>  	remote-fileio.h \
>  	remote-notif.h \
> +	riscv-fbsd-tdep.h \
>  	riscv-tdep.h \
>  	rs6000-aix-tdep.h \
>  	rs6000-tdep.h \
> @@ -2306,6 +2308,7 @@ ALLDEPFILES = \
>  	procfs.c \
>  	ravenscar-thread.c \
>  	remote-sim.c \
> +	riscv-fbsd-tdep.c \
>  	riscv-linux-nat.c \
>  	riscv-linux-tdep.c \
>  	riscv-tdep.c \
> diff --git a/gdb/NEWS b/gdb/NEWS
> index a1936ca1cc..a191ae2714 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -86,6 +86,7 @@ GNU/Linux/RISC-V		riscv*-*-linux*
>  GNU/Linux/RISC-V		riscv*-*-linux*
>  CSKY ELF			csky*-*-elf
>  CSKY GNU/LINUX			csky*-*-linux
> +FreeBSD/riscv			riscv*-*-freebsd*
>  
>  * Python API
>  
> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
> index 6d1a4df84a..3b94942732 100644
> --- a/gdb/configure.tgt
> +++ b/gdb/configure.tgt
> @@ -528,6 +528,11 @@ s390*-*-linux*)
>  	build_gdbserver=yes
>  	;;
>  
> +riscv*-*-freebsd*)
> +	# Target: FreeBSD/riscv
> +	gdb_target_obs="riscv-fbsd-tdep.o riscv-tdep.o"
> +	;;
> +
>  riscv*-*-linux*)
>  	# Target: Linux/RISC-V
>  	gdb_target_obs="riscv-linux-tdep.o riscv-tdep.o glibc-tdep.o \
> diff --git a/gdb/riscv-fbsd-tdep.c b/gdb/riscv-fbsd-tdep.c
> new file mode 100644
> index 0000000000..c09ec650ca
> --- /dev/null
> +++ b/gdb/riscv-fbsd-tdep.c
> @@ -0,0 +1,206 @@
> +/* Target-dependent code for FreeBSD on RISC-V processors.
> +   Copyright (C) 2018 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include "defs.h"
> +#include "fbsd-tdep.h"
> +#include "osabi.h"
> +#include "riscv-tdep.h"
> +#include "riscv-fbsd-tdep.h"
> +#include "solib-svr4.h"
> +#include "target.h"
> +#include "trad-frame.h"
> +#include "tramp-frame.h"
> +
> +/* Register maps.  */
> +
> +static const struct regcache_map_entry riscv_fbsd_gregmap[] =
> +  {
> +    { 1, RISCV_RA_REGNUM, 0 },
> +    { 1, RISCV_SP_REGNUM, 0 },
> +    { 1, RISCV_GP_REGNUM, 0 },
> +    { 1, RISCV_TP_REGNUM, 0 },
> +    { 3, 5, 0 },		/* t0 - t2 */
> +    { 4, 28, 0 },		/* t3 - t6 */
> +    { 2, RISCV_FP_REGNUM, 0 },	/* s0 - s1 */
> +    { 10, 18, 0 },		/* s2 - s11 */
> +    { 8, RISCV_A0_REGNUM, 0 },	/* a0 - a7 */
> +    { 1, RISCV_PC_REGNUM, 0 },
> +    { 1, RISCV_CSR_SSTATUS_REGNUM, 0 },
> +    { 0 }
> +  };
> +
> +static const struct regcache_map_entry riscv_fbsd_fpregmap[] =
> +  {
> +    { 32, RISCV_FIRST_FP_REGNUM, 16 },
> +    { 1, RISCV_CSR_FCSR_REGNUM, 8 },
> +    { 0 }
> +  };
> +
> +/* Supply the general-purpose registers stored in GREGS to REGCACHE.
> +   This function only exists to supply the always-zero x0 in addition
> +   to the registers in GREGS.  */
> +
> +static void
> +riscv_fbsd_supply_gregset (const struct regset *regset,
> +			   struct regcache *regcache, int regnum,
> +			   const void *gregs, size_t len)
> +{
> +  regcache->supply_regset (&riscv_fbsd_gregset, regnum, gregs, len);
> +  if (regnum == -1 || regnum == RISCV_ZERO_REGNUM)
> +    regcache->raw_supply_zeroed (RISCV_ZERO_REGNUM);
> +}
> +
> +/* Register set definitions.  */
> +
> +const struct regset riscv_fbsd_gregset =
> +  {
> +    riscv_fbsd_gregmap,
> +    riscv_fbsd_supply_gregset, regcache_collect_regset
> +  };
> +
> +const struct regset riscv_fbsd_fpregset =
> +  {
> +    riscv_fbsd_fpregmap,
> +    regcache_supply_regset, regcache_collect_regset
> +  };
> +
> +/* Implement the "regset_from_core_section" gdbarch method.  */
> +
> +static void
> +riscv_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
> +					 iterate_over_regset_sections_cb *cb,
> +					 void *cb_data,
> +					 const struct regcache *regcache)
> +{
> +  cb (".reg", RISCV_FBSD_NUM_GREGS * riscv_isa_xlen (gdbarch),
> +      RISCV_FBSD_NUM_GREGS * riscv_isa_xlen (gdbarch),
> +      &riscv_fbsd_gregset, NULL, cb_data);
> +  cb (".reg2", RISCV_FBSD_SIZEOF_FPREGSET, RISCV_FBSD_SIZEOF_FPREGSET,
> +      &riscv_fbsd_fpregset, NULL, cb_data);
> +}
> +
> +/* In a signal frame, sp points to a 'struct sigframe' which is
> +   defined as:
> +
> +   struct sigframe {
> +	   siginfo_t	sf_si;
> +	   ucontext_t	sf_uc;
> +   };
> +
> +   ucontext_t is defined as:
> +
> +   struct __ucontext {
> +	   sigset_t	uc_sigmask;
> +	   mcontext_t	uc_mcontext;
> +	   ...
> +   };
> +
> +   The mcontext_t contains the general purpose register set followed
> +   by the floating point register set.  The floating point register
> +   set is only valid if the _MC_FP_VALID flag is set in mc_flags.  */
> +
> +#define RISCV_SIGFRAME_UCONTEXT_OFFSET 		80
> +#define RISCV_UCONTEXT_MCONTEXT_OFFSET		16
> +#define RISCV_MCONTEXT_FLAG_FP_VALID		0x1
> +
> +/* Implement the "init" method of struct tramp_frame.  */
> +
> +static void
> +riscv_fbsd_sigframe_init (const struct tramp_frame *self,
> +			  struct frame_info *this_frame,
> +			  struct trad_frame_cache *this_cache,
> +			  CORE_ADDR func)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (this_frame);
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +  CORE_ADDR sp = get_frame_register_unsigned (this_frame, RISCV_SP_REGNUM);
> +  CORE_ADDR mcontext_addr =
> +    sp
> +    + RISCV_SIGFRAME_UCONTEXT_OFFSET
> +    + RISCV_UCONTEXT_MCONTEXT_OFFSET;
> +  gdb_byte buf[4];
> +  int i;
> +
> +  trad_frame_set_reg_regmap (this_cache, riscv_fbsd_gregmap, mcontext_addr,
> +			     RISCV_FBSD_NUM_GREGS * riscv_isa_xlen (gdbarch));
> +
> +  CORE_ADDR fpregs_addr
> +    = mcontext_addr + RISCV_FBSD_NUM_GREGS * riscv_isa_xlen (gdbarch);
> +  CORE_ADDR fp_flags_addr
> +    = fpregs_addr + RISCV_FBSD_SIZEOF_FPREGSET;
> +  if (target_read_memory (fp_flags_addr, buf, 4) == 0
> +      && (extract_unsigned_integer (buf, 4, byte_order)
> +	  & RISCV_MCONTEXT_FLAG_FP_VALID))
> +    trad_frame_set_reg_regmap (this_cache, riscv_fbsd_fpregmap, fpregs_addr,
> +			       RISCV_FBSD_SIZEOF_FPREGSET);
> +
> +  trad_frame_set_id (this_cache, frame_id_build (sp, func));
> +}
> +
> +/* RISC-V supports 16-bit instructions ("C") as well as 32-bit
> +   instructions.  The signal trampoline on FreeBSD uses a mix of
> +   these, but tramp_frame assumes a fixed instruction size.  To cope,
> +   claim that all instructions are 16 bits and use two "slots" for
> +   32-bit instructions.  */
> +
> +static const struct tramp_frame riscv_fbsd_sigframe =
> +{
> +  SIGTRAMP_FRAME,
> +  2,
> +  {
> +    {0x850a, ULONGEST_MAX},		/* mov  a0, sp  */
> +    {0x0513, ULONGEST_MAX},		/* addi a0, a0, #SF_UC  */
> +    {0x0505, ULONGEST_MAX},
> +    {0x0293, ULONGEST_MAX},		/* li   t0, #SYS_sigreturn  */
> +    {0x1a10, ULONGEST_MAX},
> +    {0x0073, ULONGEST_MAX},		/* ecall  */
> +    {0x0000, ULONGEST_MAX},
> +    {TRAMP_SENTINEL_INSN, ULONGEST_MAX}
> +  },
> +  riscv_fbsd_sigframe_init
> +};
> +
> +/* Implement the 'init_osabi' method of struct gdb_osabi_handler.  */
> +
> +static void
> +riscv_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> +{
> +  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
> +
> +  /* Generic FreeBSD support.  */
> +  fbsd_init_abi (info, gdbarch);
> +
> +  set_gdbarch_software_single_step (gdbarch, riscv_software_single_step);
> +
> +  set_solib_svr4_fetch_link_map_offsets (gdbarch,
> +					 (riscv_isa_xlen (gdbarch) == 4
> +					  ? svr4_ilp32_fetch_link_map_offsets
> +					  : svr4_lp64_fetch_link_map_offsets));
> +
> +  tramp_frame_prepend_unwinder (gdbarch, &riscv_fbsd_sigframe);
> +
> +  set_gdbarch_iterate_over_regset_sections
> +    (gdbarch, riscv_fbsd_iterate_over_regset_sections);
> +}
> +
> +void
> +_initialize_riscv_fbsd_tdep (void)
> +{
> +  gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_FREEBSD,
> +			  riscv_fbsd_init_abi);
> +}
> diff --git a/gdb/riscv-fbsd-tdep.h b/gdb/riscv-fbsd-tdep.h
> new file mode 100644
> index 0000000000..8b6abd565b
> --- /dev/null
> +++ b/gdb/riscv-fbsd-tdep.h
> @@ -0,0 +1,33 @@
> +/* FreeBSD/riscv target support, prototypes.
> +
> +   Copyright (C) 2018 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include "regset.h"
> +
> +/* The general-purpose regset consists of 31 X registers, EPC, and
> +   SSTATUS.  */
> +#define RISCV_FBSD_NUM_GREGS		33
> +
> +/* The fp regset always consists of 32 128-bit registers, plus a
> +   64-bit CSR_FCSR.  If 'Q' is not supported, only the low 64-bits of
> +   each floating point register are valid.  If 'D' is not supported,
> +   only the low 32-bits of each floating point register are valid.  */
> +#define RISCV_FBSD_SIZEOF_FPREGSET (32 * 16 + 8)
> +
> +extern const struct regset riscv_fbsd_gregset;
> +extern const struct regset riscv_fbsd_fpregset;
> -- 
> 2.18.0
>
diff mbox

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index f56b0487cc..1367f37db7 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,13 @@ 
+2018-09-24  John Baldwin  <jhb@FreeBSD.org>
+
+	* Makefile.in (ALL_TARGET_OBS): Add riscv-fbsd-tdep.o.
+	(HFILES_NO_SRCDIR): Add riscv-fbsd-tdep.h.
+	(ALLDEPFILES): Add riscv-fbsd-tdep.c.
+	* NEWS: Mention new FreeBSD/riscv target.
+	* configure.tgt: Add riscv*-*-freebsd*.
+	* riscv-fbsd-tdep.c: New file.
+	* riscv-fbsd-tdep.h: New file.
+
 2018-09-24  John Baldwin  <jhb@FreeBSD.org>
 
 	* disasm-selftests.c (print_one_insn_test): Add bfd_arch_riscv to
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 3b158fa1db..2e03bb956c 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -745,6 +745,7 @@  ALL_TARGET_OBS = \
 	ppc-sysv-tdep.o \
 	ppc64-tdep.o \
 	ravenscar-thread.o \
+	riscv-fbsd-tdep.o \
 	riscv-linux-tdep.o \
 	riscv-tdep.o \
 	rl78-tdep.o \
@@ -1339,6 +1340,7 @@  HFILES_NO_SRCDIR = \
 	remote.h \
 	remote-fileio.h \
 	remote-notif.h \
+	riscv-fbsd-tdep.h \
 	riscv-tdep.h \
 	rs6000-aix-tdep.h \
 	rs6000-tdep.h \
@@ -2306,6 +2308,7 @@  ALLDEPFILES = \
 	procfs.c \
 	ravenscar-thread.c \
 	remote-sim.c \
+	riscv-fbsd-tdep.c \
 	riscv-linux-nat.c \
 	riscv-linux-tdep.c \
 	riscv-tdep.c \
diff --git a/gdb/NEWS b/gdb/NEWS
index a1936ca1cc..a191ae2714 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -86,6 +86,7 @@  GNU/Linux/RISC-V		riscv*-*-linux*
 GNU/Linux/RISC-V		riscv*-*-linux*
 CSKY ELF			csky*-*-elf
 CSKY GNU/LINUX			csky*-*-linux
+FreeBSD/riscv			riscv*-*-freebsd*
 
 * Python API
 
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 6d1a4df84a..3b94942732 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -528,6 +528,11 @@  s390*-*-linux*)
 	build_gdbserver=yes
 	;;
 
+riscv*-*-freebsd*)
+	# Target: FreeBSD/riscv
+	gdb_target_obs="riscv-fbsd-tdep.o riscv-tdep.o"
+	;;
+
 riscv*-*-linux*)
 	# Target: Linux/RISC-V
 	gdb_target_obs="riscv-linux-tdep.o riscv-tdep.o glibc-tdep.o \
diff --git a/gdb/riscv-fbsd-tdep.c b/gdb/riscv-fbsd-tdep.c
new file mode 100644
index 0000000000..c09ec650ca
--- /dev/null
+++ b/gdb/riscv-fbsd-tdep.c
@@ -0,0 +1,206 @@ 
+/* Target-dependent code for FreeBSD on RISC-V processors.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "fbsd-tdep.h"
+#include "osabi.h"
+#include "riscv-tdep.h"
+#include "riscv-fbsd-tdep.h"
+#include "solib-svr4.h"
+#include "target.h"
+#include "trad-frame.h"
+#include "tramp-frame.h"
+
+/* Register maps.  */
+
+static const struct regcache_map_entry riscv_fbsd_gregmap[] =
+  {
+    { 1, RISCV_RA_REGNUM, 0 },
+    { 1, RISCV_SP_REGNUM, 0 },
+    { 1, RISCV_GP_REGNUM, 0 },
+    { 1, RISCV_TP_REGNUM, 0 },
+    { 3, 5, 0 },		/* t0 - t2 */
+    { 4, 28, 0 },		/* t3 - t6 */
+    { 2, RISCV_FP_REGNUM, 0 },	/* s0 - s1 */
+    { 10, 18, 0 },		/* s2 - s11 */
+    { 8, RISCV_A0_REGNUM, 0 },	/* a0 - a7 */
+    { 1, RISCV_PC_REGNUM, 0 },
+    { 1, RISCV_CSR_SSTATUS_REGNUM, 0 },
+    { 0 }
+  };
+
+static const struct regcache_map_entry riscv_fbsd_fpregmap[] =
+  {
+    { 32, RISCV_FIRST_FP_REGNUM, 16 },
+    { 1, RISCV_CSR_FCSR_REGNUM, 8 },
+    { 0 }
+  };
+
+/* Supply the general-purpose registers stored in GREGS to REGCACHE.
+   This function only exists to supply the always-zero x0 in addition
+   to the registers in GREGS.  */
+
+static void
+riscv_fbsd_supply_gregset (const struct regset *regset,
+			   struct regcache *regcache, int regnum,
+			   const void *gregs, size_t len)
+{
+  regcache->supply_regset (&riscv_fbsd_gregset, regnum, gregs, len);
+  if (regnum == -1 || regnum == RISCV_ZERO_REGNUM)
+    regcache->raw_supply_zeroed (RISCV_ZERO_REGNUM);
+}
+
+/* Register set definitions.  */
+
+const struct regset riscv_fbsd_gregset =
+  {
+    riscv_fbsd_gregmap,
+    riscv_fbsd_supply_gregset, regcache_collect_regset
+  };
+
+const struct regset riscv_fbsd_fpregset =
+  {
+    riscv_fbsd_fpregmap,
+    regcache_supply_regset, regcache_collect_regset
+  };
+
+/* Implement the "regset_from_core_section" gdbarch method.  */
+
+static void
+riscv_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
+					 iterate_over_regset_sections_cb *cb,
+					 void *cb_data,
+					 const struct regcache *regcache)
+{
+  cb (".reg", RISCV_FBSD_NUM_GREGS * riscv_isa_xlen (gdbarch),
+      RISCV_FBSD_NUM_GREGS * riscv_isa_xlen (gdbarch),
+      &riscv_fbsd_gregset, NULL, cb_data);
+  cb (".reg2", RISCV_FBSD_SIZEOF_FPREGSET, RISCV_FBSD_SIZEOF_FPREGSET,
+      &riscv_fbsd_fpregset, NULL, cb_data);
+}
+
+/* In a signal frame, sp points to a 'struct sigframe' which is
+   defined as:
+
+   struct sigframe {
+	   siginfo_t	sf_si;
+	   ucontext_t	sf_uc;
+   };
+
+   ucontext_t is defined as:
+
+   struct __ucontext {
+	   sigset_t	uc_sigmask;
+	   mcontext_t	uc_mcontext;
+	   ...
+   };
+
+   The mcontext_t contains the general purpose register set followed
+   by the floating point register set.  The floating point register
+   set is only valid if the _MC_FP_VALID flag is set in mc_flags.  */
+
+#define RISCV_SIGFRAME_UCONTEXT_OFFSET 		80
+#define RISCV_UCONTEXT_MCONTEXT_OFFSET		16
+#define RISCV_MCONTEXT_FLAG_FP_VALID		0x1
+
+/* Implement the "init" method of struct tramp_frame.  */
+
+static void
+riscv_fbsd_sigframe_init (const struct tramp_frame *self,
+			  struct frame_info *this_frame,
+			  struct trad_frame_cache *this_cache,
+			  CORE_ADDR func)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR sp = get_frame_register_unsigned (this_frame, RISCV_SP_REGNUM);
+  CORE_ADDR mcontext_addr =
+    sp
+    + RISCV_SIGFRAME_UCONTEXT_OFFSET
+    + RISCV_UCONTEXT_MCONTEXT_OFFSET;
+  gdb_byte buf[4];
+  int i;
+
+  trad_frame_set_reg_regmap (this_cache, riscv_fbsd_gregmap, mcontext_addr,
+			     RISCV_FBSD_NUM_GREGS * riscv_isa_xlen (gdbarch));
+
+  CORE_ADDR fpregs_addr
+    = mcontext_addr + RISCV_FBSD_NUM_GREGS * riscv_isa_xlen (gdbarch);
+  CORE_ADDR fp_flags_addr
+    = fpregs_addr + RISCV_FBSD_SIZEOF_FPREGSET;
+  if (target_read_memory (fp_flags_addr, buf, 4) == 0
+      && (extract_unsigned_integer (buf, 4, byte_order)
+	  & RISCV_MCONTEXT_FLAG_FP_VALID))
+    trad_frame_set_reg_regmap (this_cache, riscv_fbsd_fpregmap, fpregs_addr,
+			       RISCV_FBSD_SIZEOF_FPREGSET);
+
+  trad_frame_set_id (this_cache, frame_id_build (sp, func));
+}
+
+/* RISC-V supports 16-bit instructions ("C") as well as 32-bit
+   instructions.  The signal trampoline on FreeBSD uses a mix of
+   these, but tramp_frame assumes a fixed instruction size.  To cope,
+   claim that all instructions are 16 bits and use two "slots" for
+   32-bit instructions.  */
+
+static const struct tramp_frame riscv_fbsd_sigframe =
+{
+  SIGTRAMP_FRAME,
+  2,
+  {
+    {0x850a, ULONGEST_MAX},		/* mov  a0, sp  */
+    {0x0513, ULONGEST_MAX},		/* addi a0, a0, #SF_UC  */
+    {0x0505, ULONGEST_MAX},
+    {0x0293, ULONGEST_MAX},		/* li   t0, #SYS_sigreturn  */
+    {0x1a10, ULONGEST_MAX},
+    {0x0073, ULONGEST_MAX},		/* ecall  */
+    {0x0000, ULONGEST_MAX},
+    {TRAMP_SENTINEL_INSN, ULONGEST_MAX}
+  },
+  riscv_fbsd_sigframe_init
+};
+
+/* Implement the 'init_osabi' method of struct gdb_osabi_handler.  */
+
+static void
+riscv_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* Generic FreeBSD support.  */
+  fbsd_init_abi (info, gdbarch);
+
+  set_gdbarch_software_single_step (gdbarch, riscv_software_single_step);
+
+  set_solib_svr4_fetch_link_map_offsets (gdbarch,
+					 (riscv_isa_xlen (gdbarch) == 4
+					  ? svr4_ilp32_fetch_link_map_offsets
+					  : svr4_lp64_fetch_link_map_offsets));
+
+  tramp_frame_prepend_unwinder (gdbarch, &riscv_fbsd_sigframe);
+
+  set_gdbarch_iterate_over_regset_sections
+    (gdbarch, riscv_fbsd_iterate_over_regset_sections);
+}
+
+void
+_initialize_riscv_fbsd_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_FREEBSD,
+			  riscv_fbsd_init_abi);
+}
diff --git a/gdb/riscv-fbsd-tdep.h b/gdb/riscv-fbsd-tdep.h
new file mode 100644
index 0000000000..8b6abd565b
--- /dev/null
+++ b/gdb/riscv-fbsd-tdep.h
@@ -0,0 +1,33 @@ 
+/* FreeBSD/riscv target support, prototypes.
+
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "regset.h"
+
+/* The general-purpose regset consists of 31 X registers, EPC, and
+   SSTATUS.  */
+#define RISCV_FBSD_NUM_GREGS		33
+
+/* The fp regset always consists of 32 128-bit registers, plus a
+   64-bit CSR_FCSR.  If 'Q' is not supported, only the low 64-bits of
+   each floating point register are valid.  If 'D' is not supported,
+   only the low 32-bits of each floating point register are valid.  */
+#define RISCV_FBSD_SIZEOF_FPREGSET (32 * 16 + 8)
+
+extern const struct regset riscv_fbsd_gregset;
+extern const struct regset riscv_fbsd_fpregset;