1 /* Native-dependent code for GNU/Linux OpenRISC. 2 Copyright (C) 2021-2023 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 "regcache.h" 21 #include "gregset.h" 22 #include "linux-nat.h" 23 #include "or1k-tdep.h" 24 #include "or1k-linux-tdep.h" 25 #include "inferior.h" 26 27 #include "elf/common.h" 28 29 #include <sys/ptrace.h> 30 31 /* OpenRISC Linux native additions to the default linux support. */ 32 33 class or1k_linux_nat_target final : public linux_nat_target 34 { 35 public: 36 /* Add our register access methods. */ 37 void fetch_registers (struct regcache *regcache, int regnum) override; 38 void store_registers (struct regcache *regcache, int regnum) override; 39 40 /* Read suitable target description. */ 41 const struct target_desc *read_description () override; 42 }; 43 44 static or1k_linux_nat_target the_or1k_linux_nat_target; 45 46 /* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1) 47 from regset GREGS into REGCACHE. */ 48 49 static void 50 supply_gregset_regnum (struct regcache *regcache, const prgregset_t *gregs, 51 int regnum) 52 { 53 int i; 54 const elf_greg_t *regp = *gregs; 55 56 /* Access all registers */ 57 if (regnum == -1) 58 { 59 /* We fill the general purpose registers. */ 60 for (i = OR1K_ZERO_REGNUM + 1; i < OR1K_MAX_GPR_REGS; i++) 61 regcache->raw_supply (i, regp + i); 62 63 /* Supply OR1K_NPC_REGNUM from index 32. */ 64 regcache->raw_supply (OR1K_NPC_REGNUM, regp + 32); 65 66 /* Fill the inaccessible zero register with zero. */ 67 regcache->raw_supply_zeroed (0); 68 } 69 else if (regnum == OR1K_ZERO_REGNUM) 70 regcache->raw_supply_zeroed (0); 71 else if (regnum == OR1K_NPC_REGNUM) 72 regcache->raw_supply (OR1K_NPC_REGNUM, regp + 32); 73 else if (regnum > OR1K_ZERO_REGNUM && regnum < OR1K_MAX_GPR_REGS) 74 regcache->raw_supply (regnum, regp + regnum); 75 } 76 77 /* Copy all general purpose registers from regset GREGS into REGCACHE. */ 78 79 void 80 supply_gregset (struct regcache *regcache, const prgregset_t *gregs) 81 { 82 supply_gregset_regnum (regcache, gregs, -1); 83 } 84 85 /* Copy general purpose register REGNUM (or all gp regs if REGNUM == -1) 86 from REGCACHE into regset GREGS. */ 87 88 void 89 fill_gregset (const struct regcache *regcache, prgregset_t *gregs, int regnum) 90 { 91 elf_greg_t *regp = *gregs; 92 93 if (regnum == -1) 94 { 95 /* We fill the general purpose registers. */ 96 for (int i = OR1K_ZERO_REGNUM + 1; i < OR1K_MAX_GPR_REGS; i++) 97 regcache->raw_collect (i, regp + i); 98 99 regcache->raw_collect (OR1K_NPC_REGNUM, regp + 32); 100 } 101 else if (regnum == OR1K_ZERO_REGNUM) 102 /* Nothing to do here. */ 103 ; 104 else if (regnum > OR1K_ZERO_REGNUM && regnum < OR1K_MAX_GPR_REGS) 105 regcache->raw_collect (regnum, regp + regnum); 106 else if (regnum == OR1K_NPC_REGNUM) 107 regcache->raw_collect (OR1K_NPC_REGNUM, regp + 32); 108 } 109 110 /* Transfering floating-point registers between GDB, inferiors and cores. 111 Since OpenRISC floating-point registers are the same as GPRs these do 112 nothing. */ 113 114 void 115 supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregs) 116 { 117 } 118 119 void 120 fill_fpregset (const struct regcache *regcache, 121 gdb_fpregset_t *fpregs, int regno) 122 { 123 } 124 125 /* Return a target description for the current target. */ 126 127 const struct target_desc * 128 or1k_linux_nat_target::read_description () 129 { 130 return tdesc_or1k_linux; 131 } 132 133 /* Fetch REGNUM (or all registers if REGNUM == -1) from the target 134 into REGCACHE using PTRACE_GETREGSET. */ 135 136 void 137 or1k_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum) 138 { 139 int tid; 140 141 tid = get_ptrace_pid (regcache->ptid()); 142 143 if ((regnum >= OR1K_ZERO_REGNUM && regnum < OR1K_MAX_GPR_REGS) 144 || (regnum == OR1K_NPC_REGNUM) 145 || (regnum == -1)) 146 { 147 struct iovec iov; 148 elf_gregset_t regs; 149 150 iov.iov_base = ®s; 151 iov.iov_len = sizeof (regs); 152 153 if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, 154 (PTRACE_TYPE_ARG3) &iov) == -1) 155 perror_with_name (_("Couldn't get registers")); 156 else 157 supply_gregset_regnum (regcache, ®s, regnum); 158 } 159 160 /* Access to other SPRs has potential security issues, don't support them for 161 now. */ 162 } 163 164 /* Store REGNUM (or all registers if REGNUM == -1) to the target 165 from REGCACHE using PTRACE_SETREGSET. */ 166 167 void 168 or1k_linux_nat_target::store_registers (struct regcache *regcache, int regnum) 169 { 170 int tid; 171 172 tid = get_ptrace_pid (regcache->ptid ()); 173 174 if ((regnum >= OR1K_ZERO_REGNUM && regnum < OR1K_MAX_GPR_REGS) 175 || (regnum == OR1K_NPC_REGNUM) 176 || (regnum == -1)) 177 { 178 struct iovec iov; 179 elf_gregset_t regs; 180 181 iov.iov_base = ®s; 182 iov.iov_len = sizeof (regs); 183 184 if (ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, 185 (PTRACE_TYPE_ARG3) &iov) == -1) 186 perror_with_name (_("Couldn't get registers")); 187 else 188 { 189 fill_gregset (regcache, ®s, regnum); 190 191 if (ptrace (PTRACE_SETREGSET, tid, NT_PRSTATUS, 192 (PTRACE_TYPE_ARG3) &iov) == -1) 193 perror_with_name (_("Couldn't set registers")); 194 } 195 } 196 197 /* Access to SPRs has potential security issues, don't support them for 198 now. */ 199 } 200 201 /* Initialize OpenRISC Linux native support. */ 202 203 void _initialize_or1k_linux_nat (); 204 void 205 _initialize_or1k_linux_nat () 206 { 207 /* Register the target. */ 208 linux_target = &the_or1k_linux_nat_target; 209 add_inf_child_target (&the_or1k_linux_nat_target); 210 } 211