diff options
-rw-r--r-- | gdb/ChangeLog | 10 | ||||
-rw-r--r-- | gdb/Makefile.in | 3 | ||||
-rw-r--r-- | gdb/NEWS | 1 | ||||
-rw-r--r-- | gdb/configure.tgt | 5 | ||||
-rw-r--r-- | gdb/riscv-fbsd-tdep.c | 206 | ||||
-rw-r--r-- | gdb/riscv-fbsd-tdep.h | 33 |
6 files changed, 258 insertions, 0 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 1862ea4..b4d20bb 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -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. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 5b3a952..b1e9436 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 \ @@ -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 6d1a4df..3b94942 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 0000000..4971546 --- /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 0000000..8b6abd5 --- /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; |