Home | History | Annotate | Line # | Download | only in gdb
      1 /* Target-dependent code for NetBSD on RISC-V processors.
      2    Copyright (C) 2018-2020 Free Software Foundation, Inc.
      3 
      4    This file is part of GDB.
      5 
      6    This program is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by
      8    the Free Software Foundation; either version 3 of the License, or
      9    (at your option) any later version.
     10 
     11    This program is distributed in the hope that it will be useful,
     12    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14    GNU General Public License for more details.
     15 
     16    You should have received a copy of the GNU General Public License
     17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     18 
     19 #include "defs.h"
     20 #include "netbsd-tdep.h"
     21 #include "extract-store-integer.h"
     22 #include "osabi.h"
     23 #include "riscv-tdep.h"
     24 #include "riscv-netbsd-tdep.h"
     25 #include "solib-svr4.h"
     26 #include "target.h"
     27 #include "trad-frame.h"
     28 #include "tramp-frame.h"
     29 #include "gdbarch.h"
     30 #include "inferior.h"
     31 
     32 /* Register maps.  */
     33 
     34 static const struct regcache_map_entry riscv_nbsd_gregmap[] =
     35   {
     36     { 31, RISCV_RA_REGNUM, 0 }, /* x1 to x31 */
     37     { 1,  RISCV_PC_REGNUM, 0 },
     38     { 0 }
     39   };
     40 
     41 static const struct regcache_map_entry riscv_nbsd_fpregmap[] =
     42   {
     43     { 32, RISCV_FIRST_FP_REGNUM, 16 },
     44     { 1, RISCV_CSR_FCSR_REGNUM, 8 },
     45     { 0 }
     46   };
     47 
     48 /* Supply the general-purpose registers stored in GREGS to REGCACHE.
     49    This function only exists to supply the always-zero x0 in addition
     50    to the registers in GREGS.  */
     51 
     52 static void
     53 riscv_nbsd_supply_gregset (const struct regset *regset,
     54 			   struct regcache *regcache, int regnum,
     55 			   const void *gregs, size_t len)
     56 {
     57   regcache->supply_regset (&riscv_nbsd_gregset, regnum, gregs, len);
     58   if (regnum == -1 || regnum == RISCV_ZERO_REGNUM)
     59     regcache->raw_supply_zeroed (RISCV_ZERO_REGNUM);
     60 }
     61 
     62 /* Register set definitions.  */
     63 
     64 const struct regset riscv_nbsd_gregset =
     65   {
     66     riscv_nbsd_gregmap,
     67     riscv_nbsd_supply_gregset, regcache_collect_regset
     68   };
     69 
     70 const struct regset riscv_nbsd_fpregset =
     71   {
     72     riscv_nbsd_fpregmap,
     73     regcache_supply_regset, regcache_collect_regset
     74   };
     75 
     76 /* Implement the "iterate_over_regset_sections" gdbarch method.  */
     77 
     78 static void
     79 riscv_nbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
     80 					 iterate_over_regset_sections_cb *cb,
     81 					 void *cb_data,
     82 					 const struct regcache *regcache)
     83 {
     84   cb (".reg", RISCV_NBSD_NUM_GREGS * riscv_isa_xlen (gdbarch),
     85       RISCV_NBSD_NUM_GREGS * riscv_isa_xlen (gdbarch),
     86       &riscv_nbsd_gregset, NULL, cb_data);
     87   cb (".reg2", RISCV_NBSD_SIZEOF_FPREGSET, RISCV_NBSD_SIZEOF_FPREGSET,
     88       &riscv_nbsd_fpregset, NULL, cb_data);
     89 }
     90 
     91 /* In a signal frame, sp points to a 'struct sigframe' which is
     92    defined as:
     93 
     94    struct sigframe {
     95 	   siginfo_t	sf_si;
     96 	   ucontext_t	sf_uc;
     97    };
     98 
     99    ucontext_t is defined as:
    100 
    101    struct __ucontext {
    102 	   sigset_t	uc_sigmask;
    103 	   mcontext_t	uc_mcontext;
    104 	   ...
    105    };
    106 
    107    The mcontext_t contains the general purpose register set followed
    108    by the floating point register set.  The floating point register
    109    set is only valid if the _MC_FP_VALID flag is set in mc_flags.  */
    110 
    111 #define RISCV_SIGFRAME_UCONTEXT_OFFSET 		80
    112 #define RISCV_UCONTEXT_MCONTEXT_OFFSET		16
    113 #define RISCV_MCONTEXT_FLAG_FP_VALID		0x1
    114 
    115 /* Implement the "init" method of struct tramp_frame.  */
    116 
    117 static void
    118 riscv_nbsd_sigframe_init (const struct tramp_frame *self,
    119 			  const frame_info_ptr& this_frame,
    120 			  struct trad_frame_cache *this_cache,
    121 			  CORE_ADDR func)
    122 {
    123   struct gdbarch *gdbarch = get_frame_arch (this_frame);
    124   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
    125   CORE_ADDR sp = get_frame_register_unsigned (this_frame, RISCV_SP_REGNUM);
    126   CORE_ADDR mcontext_addr
    127     = (sp
    128        + RISCV_SIGFRAME_UCONTEXT_OFFSET
    129        + RISCV_UCONTEXT_MCONTEXT_OFFSET);
    130   gdb_byte buf[4];
    131 
    132   trad_frame_set_reg_regmap (this_cache, riscv_nbsd_gregmap, mcontext_addr,
    133 			     RISCV_NBSD_NUM_GREGS * riscv_isa_xlen (gdbarch));
    134 
    135   CORE_ADDR fpregs_addr
    136     = mcontext_addr + RISCV_NBSD_NUM_GREGS * riscv_isa_xlen (gdbarch);
    137   CORE_ADDR fp_flags_addr
    138     = fpregs_addr + RISCV_NBSD_SIZEOF_FPREGSET;
    139   if (target_read_memory (fp_flags_addr, buf, 4) == 0
    140       && (extract_unsigned_integer (buf, 4, byte_order)
    141 	  & RISCV_MCONTEXT_FLAG_FP_VALID))
    142     trad_frame_set_reg_regmap (this_cache, riscv_nbsd_fpregmap, fpregs_addr,
    143 			       RISCV_NBSD_SIZEOF_FPREGSET);
    144 
    145   trad_frame_set_id (this_cache, frame_id_build (sp, func));
    146 }
    147 
    148 /* RISC-V supports 16-bit instructions ("C") as well as 32-bit
    149    instructions.  The signal trampoline on NetBSD uses a mix of
    150    these, but tramp_frame assumes a fixed instruction size.  To cope,
    151    claim that all instructions are 16 bits and use two "slots" for
    152    32-bit instructions.  */
    153 
    154 static const struct tramp_frame riscv_nbsd_sigframe =
    155 {
    156   SIGTRAMP_FRAME,
    157   2,
    158   {
    159     {0x850a, ULONGEST_MAX},		/* mov  a0, sp  */
    160     {0x0513, ULONGEST_MAX},		/* addi a0, a0, #SF_UC  */
    161     {0x0505, ULONGEST_MAX},
    162     {0x0293, ULONGEST_MAX},		/* li   t0, #SYS_sigreturn  */
    163     {0x1a10, ULONGEST_MAX},
    164     {0x0073, ULONGEST_MAX},		/* ecall  */
    165     {0x0000, ULONGEST_MAX},
    166     {TRAMP_SENTINEL_INSN, ULONGEST_MAX}
    167   },
    168   riscv_nbsd_sigframe_init
    169 };
    170 
    171 
    172 #if 0
    173 /* Implement the "get_thread_local_address" gdbarch method.  */
    174 
    175 static CORE_ADDR
    176 riscv_nbsd_get_thread_local_address (struct gdbarch *gdbarch, ptid_t ptid,
    177 				     CORE_ADDR lm_addr, CORE_ADDR offset)
    178 {
    179   struct regcache *regcache;
    180 
    181   regcache = get_thread_arch_regcache (current_inferior ()->process_target (),
    182 				       ptid, gdbarch);
    183 
    184   target_fetch_registers (regcache, RISCV_TP_REGNUM);
    185 
    186   ULONGEST tp;
    187   if (regcache->cooked_read (RISCV_TP_REGNUM, &tp) != REG_VALID)
    188     error (_("Unable to fetch %%tp"));
    189 
    190   /* %tp points to the end of the TCB which contains two pointers.
    191       The first pointer in the TCB points to the DTV array.  */
    192   CORE_ADDR dtv_addr = tp - (gdbarch_ptr_bit (gdbarch) / 8) * 2;
    193   return nbsd_get_thread_local_address (gdbarch, dtv_addr, lm_addr, offset);
    194 }
    195 #endif
    196 
    197 
    198 /* Implement the 'init_osabi' method of struct gdb_osabi_handler.  */
    199 
    200 static void
    201 riscv_nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
    202 {
    203   /* Generic NetBSD support.  */
    204   nbsd_init_abi (info, gdbarch);
    205 
    206   set_gdbarch_software_single_step (gdbarch, riscv_software_single_step);
    207 
    208   set_solib_svr4_fetch_link_map_offsets (gdbarch,
    209 					 (riscv_isa_xlen (gdbarch) == 4
    210 					  ? svr4_ilp32_fetch_link_map_offsets
    211 					  : svr4_lp64_fetch_link_map_offsets));
    212 
    213   tramp_frame_prepend_unwinder (gdbarch, &riscv_nbsd_sigframe);
    214 
    215   set_gdbarch_iterate_over_regset_sections
    216     (gdbarch, riscv_nbsd_iterate_over_regset_sections);
    217 
    218   set_gdbarch_fetch_tls_load_module_address (gdbarch,
    219 					     svr4_fetch_objfile_link_map);
    220 #if 0
    221   set_gdbarch_get_thread_local_address (gdbarch,
    222 					riscv_nbsd_get_thread_local_address);
    223 #endif
    224 }
    225 
    226 void _initialize_riscv_nbsd_tdep ();
    227 void
    228 _initialize_riscv_nbsd_tdep ()
    229 {
    230   gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_NETBSD,
    231 			  riscv_nbsd_init_abi);
    232 }
    233