17f2ac410Schristos /* Target-dependent code for FreeBSD on RISC-V processors. 2*6881a400Schristos Copyright (C) 2018-2023 Free Software Foundation, Inc. 37f2ac410Schristos 47f2ac410Schristos This file is part of GDB. 57f2ac410Schristos 67f2ac410Schristos This program is free software; you can redistribute it and/or modify 77f2ac410Schristos it under the terms of the GNU General Public License as published by 87f2ac410Schristos the Free Software Foundation; either version 3 of the License, or 97f2ac410Schristos (at your option) any later version. 107f2ac410Schristos 117f2ac410Schristos This program is distributed in the hope that it will be useful, 127f2ac410Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 137f2ac410Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 147f2ac410Schristos GNU General Public License for more details. 157f2ac410Schristos 167f2ac410Schristos You should have received a copy of the GNU General Public License 177f2ac410Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 187f2ac410Schristos 197f2ac410Schristos #include "defs.h" 207f2ac410Schristos #include "fbsd-tdep.h" 217f2ac410Schristos #include "osabi.h" 227f2ac410Schristos #include "riscv-tdep.h" 237f2ac410Schristos #include "riscv-fbsd-tdep.h" 247f2ac410Schristos #include "solib-svr4.h" 257f2ac410Schristos #include "target.h" 267f2ac410Schristos #include "trad-frame.h" 277f2ac410Schristos #include "tramp-frame.h" 287d62b00eSchristos #include "gdbarch.h" 297d62b00eSchristos #include "inferior.h" 307f2ac410Schristos 317f2ac410Schristos /* Register maps. */ 327f2ac410Schristos 337f2ac410Schristos static const struct regcache_map_entry riscv_fbsd_gregmap[] = 347f2ac410Schristos { 357f2ac410Schristos { 1, RISCV_RA_REGNUM, 0 }, 367f2ac410Schristos { 1, RISCV_SP_REGNUM, 0 }, 377f2ac410Schristos { 1, RISCV_GP_REGNUM, 0 }, 387f2ac410Schristos { 1, RISCV_TP_REGNUM, 0 }, 397f2ac410Schristos { 3, 5, 0 }, /* t0 - t2 */ 407f2ac410Schristos { 4, 28, 0 }, /* t3 - t6 */ 417f2ac410Schristos { 2, RISCV_FP_REGNUM, 0 }, /* s0 - s1 */ 427f2ac410Schristos { 10, 18, 0 }, /* s2 - s11 */ 437f2ac410Schristos { 8, RISCV_A0_REGNUM, 0 }, /* a0 - a7 */ 447f2ac410Schristos { 1, RISCV_PC_REGNUM, 0 }, 457f2ac410Schristos { 1, RISCV_CSR_SSTATUS_REGNUM, 0 }, 467f2ac410Schristos { 0 } 477f2ac410Schristos }; 487f2ac410Schristos 497f2ac410Schristos static const struct regcache_map_entry riscv_fbsd_fpregmap[] = 507f2ac410Schristos { 517f2ac410Schristos { 32, RISCV_FIRST_FP_REGNUM, 16 }, 527f2ac410Schristos { 1, RISCV_CSR_FCSR_REGNUM, 8 }, 537f2ac410Schristos { 0 } 547f2ac410Schristos }; 557f2ac410Schristos 567f2ac410Schristos /* Register set definitions. */ 577f2ac410Schristos 587f2ac410Schristos const struct regset riscv_fbsd_gregset = 597f2ac410Schristos { 60*6881a400Schristos riscv_fbsd_gregmap, riscv_supply_regset, regcache_collect_regset 617f2ac410Schristos }; 627f2ac410Schristos 637f2ac410Schristos const struct regset riscv_fbsd_fpregset = 647f2ac410Schristos { 65*6881a400Schristos riscv_fbsd_fpregmap, riscv_supply_regset, regcache_collect_regset 667f2ac410Schristos }; 677f2ac410Schristos 687d62b00eSchristos /* Implement the "iterate_over_regset_sections" gdbarch method. */ 697f2ac410Schristos 707f2ac410Schristos static void 717f2ac410Schristos riscv_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, 727f2ac410Schristos iterate_over_regset_sections_cb *cb, 737f2ac410Schristos void *cb_data, 747f2ac410Schristos const struct regcache *regcache) 757f2ac410Schristos { 767f2ac410Schristos cb (".reg", RISCV_FBSD_NUM_GREGS * riscv_isa_xlen (gdbarch), 777f2ac410Schristos RISCV_FBSD_NUM_GREGS * riscv_isa_xlen (gdbarch), 787f2ac410Schristos &riscv_fbsd_gregset, NULL, cb_data); 797f2ac410Schristos cb (".reg2", RISCV_FBSD_SIZEOF_FPREGSET, RISCV_FBSD_SIZEOF_FPREGSET, 807f2ac410Schristos &riscv_fbsd_fpregset, NULL, cb_data); 817f2ac410Schristos } 827f2ac410Schristos 837f2ac410Schristos /* In a signal frame, sp points to a 'struct sigframe' which is 847f2ac410Schristos defined as: 857f2ac410Schristos 867f2ac410Schristos struct sigframe { 877f2ac410Schristos siginfo_t sf_si; 887f2ac410Schristos ucontext_t sf_uc; 897f2ac410Schristos }; 907f2ac410Schristos 917f2ac410Schristos ucontext_t is defined as: 927f2ac410Schristos 937f2ac410Schristos struct __ucontext { 947f2ac410Schristos sigset_t uc_sigmask; 957f2ac410Schristos mcontext_t uc_mcontext; 967f2ac410Schristos ... 977f2ac410Schristos }; 987f2ac410Schristos 997f2ac410Schristos The mcontext_t contains the general purpose register set followed 1007f2ac410Schristos by the floating point register set. The floating point register 1017f2ac410Schristos set is only valid if the _MC_FP_VALID flag is set in mc_flags. */ 1027f2ac410Schristos 1037f2ac410Schristos #define RISCV_SIGFRAME_UCONTEXT_OFFSET 80 1047f2ac410Schristos #define RISCV_UCONTEXT_MCONTEXT_OFFSET 16 1057f2ac410Schristos #define RISCV_MCONTEXT_FLAG_FP_VALID 0x1 1067f2ac410Schristos 1077f2ac410Schristos /* Implement the "init" method of struct tramp_frame. */ 1087f2ac410Schristos 1097f2ac410Schristos static void 1107f2ac410Schristos riscv_fbsd_sigframe_init (const struct tramp_frame *self, 111*6881a400Schristos frame_info_ptr this_frame, 1127f2ac410Schristos struct trad_frame_cache *this_cache, 1137f2ac410Schristos CORE_ADDR func) 1147f2ac410Schristos { 1157f2ac410Schristos struct gdbarch *gdbarch = get_frame_arch (this_frame); 1167f2ac410Schristos enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 1177f2ac410Schristos CORE_ADDR sp = get_frame_register_unsigned (this_frame, RISCV_SP_REGNUM); 1187f2ac410Schristos CORE_ADDR mcontext_addr 1197f2ac410Schristos = (sp 1207f2ac410Schristos + RISCV_SIGFRAME_UCONTEXT_OFFSET 1217f2ac410Schristos + RISCV_UCONTEXT_MCONTEXT_OFFSET); 1227f2ac410Schristos gdb_byte buf[4]; 1237f2ac410Schristos 1247f2ac410Schristos trad_frame_set_reg_regmap (this_cache, riscv_fbsd_gregmap, mcontext_addr, 1257f2ac410Schristos RISCV_FBSD_NUM_GREGS * riscv_isa_xlen (gdbarch)); 1267f2ac410Schristos 1277f2ac410Schristos CORE_ADDR fpregs_addr 1287f2ac410Schristos = mcontext_addr + RISCV_FBSD_NUM_GREGS * riscv_isa_xlen (gdbarch); 1297f2ac410Schristos CORE_ADDR fp_flags_addr 1307f2ac410Schristos = fpregs_addr + RISCV_FBSD_SIZEOF_FPREGSET; 1317f2ac410Schristos if (target_read_memory (fp_flags_addr, buf, 4) == 0 1327f2ac410Schristos && (extract_unsigned_integer (buf, 4, byte_order) 1337f2ac410Schristos & RISCV_MCONTEXT_FLAG_FP_VALID)) 1347f2ac410Schristos trad_frame_set_reg_regmap (this_cache, riscv_fbsd_fpregmap, fpregs_addr, 1357f2ac410Schristos RISCV_FBSD_SIZEOF_FPREGSET); 1367f2ac410Schristos 1377f2ac410Schristos trad_frame_set_id (this_cache, frame_id_build (sp, func)); 1387f2ac410Schristos } 1397f2ac410Schristos 1407f2ac410Schristos /* RISC-V supports 16-bit instructions ("C") as well as 32-bit 1417f2ac410Schristos instructions. The signal trampoline on FreeBSD uses a mix of 1427f2ac410Schristos these, but tramp_frame assumes a fixed instruction size. To cope, 1437f2ac410Schristos claim that all instructions are 16 bits and use two "slots" for 1447f2ac410Schristos 32-bit instructions. */ 1457f2ac410Schristos 1467f2ac410Schristos static const struct tramp_frame riscv_fbsd_sigframe = 1477f2ac410Schristos { 1487f2ac410Schristos SIGTRAMP_FRAME, 1497f2ac410Schristos 2, 1507f2ac410Schristos { 1517f2ac410Schristos {0x850a, ULONGEST_MAX}, /* mov a0, sp */ 1527f2ac410Schristos {0x0513, ULONGEST_MAX}, /* addi a0, a0, #SF_UC */ 1537f2ac410Schristos {0x0505, ULONGEST_MAX}, 1547f2ac410Schristos {0x0293, ULONGEST_MAX}, /* li t0, #SYS_sigreturn */ 1557f2ac410Schristos {0x1a10, ULONGEST_MAX}, 1567f2ac410Schristos {0x0073, ULONGEST_MAX}, /* ecall */ 1577f2ac410Schristos {0x0000, ULONGEST_MAX}, 1587f2ac410Schristos {TRAMP_SENTINEL_INSN, ULONGEST_MAX} 1597f2ac410Schristos }, 1607f2ac410Schristos riscv_fbsd_sigframe_init 1617f2ac410Schristos }; 1627f2ac410Schristos 1637d62b00eSchristos /* Implement the "get_thread_local_address" gdbarch method. */ 1647d62b00eSchristos 1657d62b00eSchristos static CORE_ADDR 1667d62b00eSchristos riscv_fbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid, 1677d62b00eSchristos CORE_ADDR lm_addr, CORE_ADDR offset) 1687d62b00eSchristos { 1697d62b00eSchristos struct regcache *regcache; 1707d62b00eSchristos 1717d62b00eSchristos regcache = get_thread_arch_regcache (current_inferior ()->process_target (), 1727d62b00eSchristos ptid, gdbarch); 1737d62b00eSchristos 1747d62b00eSchristos target_fetch_registers (regcache, RISCV_TP_REGNUM); 1757d62b00eSchristos 1767d62b00eSchristos ULONGEST tp; 1777d62b00eSchristos if (regcache->cooked_read (RISCV_TP_REGNUM, &tp) != REG_VALID) 1787d62b00eSchristos error (_("Unable to fetch %%tp")); 1797d62b00eSchristos 1807d62b00eSchristos /* %tp points to the end of the TCB which contains two pointers. 1817d62b00eSchristos The first pointer in the TCB points to the DTV array. */ 1827d62b00eSchristos CORE_ADDR dtv_addr = tp - (gdbarch_ptr_bit (gdbarch) / 8) * 2; 1837d62b00eSchristos return fbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset); 1847d62b00eSchristos } 1857d62b00eSchristos 1867f2ac410Schristos /* Implement the 'init_osabi' method of struct gdb_osabi_handler. */ 1877f2ac410Schristos 1887f2ac410Schristos static void 1897f2ac410Schristos riscv_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 1907f2ac410Schristos { 1917f2ac410Schristos /* Generic FreeBSD support. */ 1927f2ac410Schristos fbsd_init_abi (info, gdbarch); 1937f2ac410Schristos 1947f2ac410Schristos set_gdbarch_software_single_step (gdbarch, riscv_software_single_step); 1957f2ac410Schristos 1967f2ac410Schristos set_solib_svr4_fetch_link_map_offsets (gdbarch, 1977f2ac410Schristos (riscv_isa_xlen (gdbarch) == 4 1987f2ac410Schristos ? svr4_ilp32_fetch_link_map_offsets 1997f2ac410Schristos : svr4_lp64_fetch_link_map_offsets)); 2007f2ac410Schristos 2017f2ac410Schristos tramp_frame_prepend_unwinder (gdbarch, &riscv_fbsd_sigframe); 2027f2ac410Schristos 2037f2ac410Schristos set_gdbarch_iterate_over_regset_sections 2047f2ac410Schristos (gdbarch, riscv_fbsd_iterate_over_regset_sections); 2057d62b00eSchristos 2067d62b00eSchristos set_gdbarch_fetch_tls_load_module_address (gdbarch, 2077d62b00eSchristos svr4_fetch_objfile_link_map); 2087d62b00eSchristos set_gdbarch_get_thread_local_address (gdbarch, 2097d62b00eSchristos riscv_fbsd_get_thread_local_address); 2107f2ac410Schristos } 2117f2ac410Schristos 2127d62b00eSchristos void _initialize_riscv_fbsd_tdep (); 2137f2ac410Schristos void 2147d62b00eSchristos _initialize_riscv_fbsd_tdep () 2157f2ac410Schristos { 2167f2ac410Schristos gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_FREEBSD, 2177f2ac410Schristos riscv_fbsd_init_abi); 2187f2ac410Schristos } 219