From ed65e20bc7cd18406081cf5ba29f9c9bccd4e52f Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 8 Oct 2018 14:47:34 -0700 Subject: [PATCH] Add FreeBSD/riscv architecture. 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 diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 1862ea48811..b4d20bbca07 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2018-10-08 John Baldwin + + * 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 * regcache.h (struct regcache_map_entry): Note that this type can diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 5b3a952fce8..b1e94364376 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -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 \ diff --git a/gdb/NEWS b/gdb/NEWS index f3bdeeaf720..345e450fa7c 100644 --- 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 diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 6d1a4df84ac..3b94942732a 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 00000000000..4971546c1e4 --- /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 . */ + +#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 00000000000..8b6abd565b9 --- /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 . */ + +#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.30.2