Add FreeBSD/riscv architecture.
authorJohn Baldwin <jhb@FreeBSD.org>
Mon, 8 Oct 2018 21:47:34 +0000 (14:47 -0700)
committerJohn Baldwin <jhb@FreeBSD.org>
Mon, 8 Oct 2018 21:47:34 +0000 (14:47 -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.

gdb/ChangeLog
gdb/Makefile.in
gdb/NEWS
gdb/configure.tgt
gdb/riscv-fbsd-tdep.c [new file with mode: 0644]
gdb/riscv-fbsd-tdep.h [new file with mode: 0644]

index 1862ea4..b4d20bb 100644 (file)
@@ -1,5 +1,15 @@
 2018-10-08  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-10-08  John Baldwin  <jhb@FreeBSD.org>
+
        * regcache.h (struct regcache_map_entry): Note that this type can
        be used with traditional frame caches.
        * trad-frame.c (trad_frame_set_reg_regmap): New.
index 5b3a952..b1e9436 100644 (file)
@@ -744,6 +744,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 \
@@ -1338,6 +1339,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 \
index f3bdeea..345e450 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -99,6 +99,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
 
index 6d1a4df..3b94942 100644 (file)
@@ -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 (file)
index 0000000..4971546
--- /dev/null
@@ -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 (file)
index 0000000..8b6abd5
--- /dev/null
@@ -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;