Commit | Line | Data |
---|---|---|
e7a42bc8 | 1 | /* Native-dependent code for BSD Unix running on ARM's, for GDB. |
9f8e0089 | 2 | |
3666a048 | 3 | Copyright (C) 1988-2021 Free Software Foundation, Inc. |
e7a42bc8 FN |
4 | |
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
a9762ec7 | 9 | the Free Software Foundation; either version 3 of the License, or |
e7a42bc8 FN |
10 | (at your option) any later version. |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
a9762ec7 | 18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
e7a42bc8 | 19 | |
73685c7e CB |
20 | /* We define this to get types like register_t. */ |
21 | #define _KERNTYPES | |
e7a42bc8 | 22 | #include "defs.h" |
d55e5aa6 | 23 | #include "gdbcore.h" |
d55e5aa6 TT |
24 | #include "inferior.h" |
25 | #include "regcache.h" | |
26 | #include "target.h" | |
4de283e4 TT |
27 | #include <sys/types.h> |
28 | #include <sys/ptrace.h> | |
81b86b97 | 29 | #include <sys/sysctl.h> |
4de283e4 TT |
30 | #include <machine/reg.h> |
31 | #include <machine/frame.h> | |
32 | ||
33 | #include "arm-tdep.h" | |
1b71cfcf | 34 | #include "arm-netbsd-tdep.h" |
81b86b97 | 35 | #include "aarch32-tdep.h" |
4de283e4 | 36 | #include "inf-ptrace.h" |
1b71cfcf | 37 | #include "netbsd-nat.h" |
e7a42bc8 | 38 | |
6018d381 | 39 | class arm_netbsd_nat_target final : public nbsd_nat_target |
f6ac5f3d PA |
40 | { |
41 | public: | |
42 | /* Add our register access methods. */ | |
43 | void fetch_registers (struct regcache *, int) override; | |
44 | void store_registers (struct regcache *, int) override; | |
81b86b97 | 45 | const struct target_desc *read_description () override; |
f6ac5f3d PA |
46 | }; |
47 | ||
48 | static arm_netbsd_nat_target the_arm_netbsd_nat_target; | |
49 | ||
b34db576 | 50 | static void |
81b86b97 | 51 | arm_supply_vfpregset (struct regcache *regcache, struct fpreg *fpregset) |
b34db576 | 52 | { |
81b86b97 CB |
53 | struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); |
54 | if (tdep->vfp_register_count == 0) | |
55 | return; | |
b34db576 | 56 | |
81b86b97 CB |
57 | struct vfpreg &vfp = fpregset->fpr_vfp; |
58 | for (int regno = 0; regno <= tdep->vfp_register_count; regno++) | |
59 | regcache->raw_supply (regno + ARM_D0_REGNUM, (char *) &vfp.vfp_regs[regno]); | |
b34db576 | 60 | |
81b86b97 | 61 | regcache->raw_supply (ARM_FPSCR_REGNUM, (char *) &vfp.vfp_fpscr); |
b34db576 RE |
62 | } |
63 | ||
47221191 | 64 | static void |
56be3814 | 65 | fetch_register (struct regcache *regcache, int regno) |
47221191 RE |
66 | { |
67 | struct reg inferior_registers; | |
68 | int ret; | |
75c56d3d | 69 | int lwp = regcache->ptid ().lwp (); |
47221191 | 70 | |
e99b03dc | 71 | ret = ptrace (PT_GETREGS, regcache->ptid ().pid (), |
75c56d3d | 72 | (PTRACE_TYPE_ARG3) &inferior_registers, lwp); |
47221191 RE |
73 | |
74 | if (ret < 0) | |
75 | { | |
edefbb7c | 76 | warning (_("unable to fetch general register")); |
47221191 RE |
77 | return; |
78 | } | |
8dd8e1c7 CB |
79 | arm_nbsd_supply_gregset (nullptr, regcache, regno, &inferior_registers, |
80 | sizeof (inferior_registers)); | |
47221191 RE |
81 | } |
82 | ||
83 | static void | |
56be3814 | 84 | fetch_fp_register (struct regcache *regcache, int regno) |
47221191 RE |
85 | { |
86 | struct fpreg inferior_fp_registers; | |
75c56d3d KR |
87 | int lwp = regcache->ptid ().lwp (); |
88 | ||
81b86b97 | 89 | int ret = ptrace (PT_GETFPREGS, regcache->ptid ().pid (), |
75c56d3d | 90 | (PTRACE_TYPE_ARG3) &inferior_fp_registers, lwp); |
47221191 | 91 | |
81b86b97 | 92 | struct vfpreg &vfp = inferior_fp_registers.fpr_vfp; |
47221191 RE |
93 | |
94 | if (ret < 0) | |
95 | { | |
edefbb7c | 96 | warning (_("unable to fetch floating-point register")); |
47221191 RE |
97 | return; |
98 | } | |
99 | ||
81b86b97 CB |
100 | struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); |
101 | if (regno == ARM_FPSCR_REGNUM && tdep->vfp_register_count != 0) | |
102 | regcache->raw_supply (ARM_FPSCR_REGNUM, (char *) &vfp.vfp_fpscr); | |
103 | else if (regno >= ARM_D0_REGNUM | |
104 | && regno <= ARM_D0_REGNUM + tdep->vfp_register_count) | |
47221191 | 105 | { |
81b86b97 CB |
106 | regcache->raw_supply (regno, |
107 | (char *) &vfp.vfp_regs[regno - ARM_D0_REGNUM]); | |
47221191 | 108 | } |
81b86b97 CB |
109 | else |
110 | warning (_("Invalid register number.")); | |
47221191 RE |
111 | } |
112 | ||
113 | static void | |
56be3814 | 114 | fetch_fp_regs (struct regcache *regcache) |
47221191 RE |
115 | { |
116 | struct fpreg inferior_fp_registers; | |
75c56d3d | 117 | int lwp = regcache->ptid ().lwp (); |
47221191 RE |
118 | int ret; |
119 | int regno; | |
120 | ||
e99b03dc | 121 | ret = ptrace (PT_GETFPREGS, regcache->ptid ().pid (), |
75c56d3d | 122 | (PTRACE_TYPE_ARG3) &inferior_fp_registers, lwp); |
47221191 RE |
123 | |
124 | if (ret < 0) | |
125 | { | |
edefbb7c | 126 | warning (_("unable to fetch general registers")); |
47221191 RE |
127 | return; |
128 | } | |
129 | ||
81b86b97 | 130 | arm_supply_vfpregset (regcache, &inferior_fp_registers); |
e7a42bc8 FN |
131 | } |
132 | ||
f6ac5f3d | 133 | void |
3050c6f4 | 134 | arm_netbsd_nat_target::fetch_registers (struct regcache *regcache, int regno) |
47221191 RE |
135 | { |
136 | if (regno >= 0) | |
137 | { | |
138 | if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM) | |
56be3814 | 139 | fetch_register (regcache, regno); |
47221191 | 140 | else |
56be3814 | 141 | fetch_fp_register (regcache, regno); |
47221191 RE |
142 | } |
143 | else | |
144 | { | |
8dd8e1c7 | 145 | fetch_register (regcache, -1); |
56be3814 | 146 | fetch_fp_regs (regcache); |
47221191 RE |
147 | } |
148 | } | |
149 | ||
150 | ||
151 | static void | |
56be3814 | 152 | store_register (const struct regcache *regcache, int regno) |
e7a42bc8 | 153 | { |
ac7936df | 154 | struct gdbarch *gdbarch = regcache->arch (); |
e7a42bc8 | 155 | struct reg inferior_registers; |
75c56d3d | 156 | int lwp = regcache->ptid ().lwp (); |
47221191 RE |
157 | int ret; |
158 | ||
e99b03dc | 159 | ret = ptrace (PT_GETREGS, regcache->ptid ().pid (), |
75c56d3d | 160 | (PTRACE_TYPE_ARG3) &inferior_registers, lwp); |
47221191 RE |
161 | |
162 | if (ret < 0) | |
163 | { | |
edefbb7c | 164 | warning (_("unable to fetch general registers")); |
47221191 RE |
165 | return; |
166 | } | |
167 | ||
168 | switch (regno) | |
169 | { | |
170 | case ARM_SP_REGNUM: | |
34a79281 | 171 | regcache->raw_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp); |
47221191 RE |
172 | break; |
173 | ||
174 | case ARM_LR_REGNUM: | |
34a79281 | 175 | regcache->raw_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr); |
47221191 | 176 | break; |
e7a42bc8 | 177 | |
47221191 RE |
178 | case ARM_PC_REGNUM: |
179 | if (arm_apcs_32) | |
34a79281 SM |
180 | regcache->raw_collect (ARM_PC_REGNUM, |
181 | (char *) &inferior_registers.r_pc); | |
47221191 RE |
182 | else |
183 | { | |
184 | unsigned pc_val; | |
e7a42bc8 | 185 | |
34a79281 | 186 | regcache->raw_collect (ARM_PC_REGNUM, (char *) &pc_val); |
47221191 | 187 | |
b2cb219a | 188 | pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val); |
bf6ae464 | 189 | inferior_registers.r_pc ^= gdbarch_addr_bits_remove |
b2cb219a | 190 | (gdbarch, inferior_registers.r_pc); |
47221191 RE |
191 | inferior_registers.r_pc |= pc_val; |
192 | } | |
193 | break; | |
194 | ||
195 | case ARM_PS_REGNUM: | |
196 | if (arm_apcs_32) | |
34a79281 SM |
197 | regcache->raw_collect (ARM_PS_REGNUM, |
198 | (char *) &inferior_registers.r_cpsr); | |
47221191 RE |
199 | else |
200 | { | |
201 | unsigned psr_val; | |
202 | ||
34a79281 | 203 | regcache->raw_collect (ARM_PS_REGNUM, (char *) &psr_val); |
47221191 | 204 | |
b2cb219a | 205 | psr_val ^= gdbarch_addr_bits_remove (gdbarch, psr_val); |
bf6ae464 | 206 | inferior_registers.r_pc = gdbarch_addr_bits_remove |
b2cb219a | 207 | (gdbarch, inferior_registers.r_pc); |
47221191 RE |
208 | inferior_registers.r_pc |= psr_val; |
209 | } | |
210 | break; | |
211 | ||
212 | default: | |
34a79281 | 213 | regcache->raw_collect (regno, (char *) &inferior_registers.r[regno]); |
47221191 RE |
214 | break; |
215 | } | |
216 | ||
e99b03dc | 217 | ret = ptrace (PT_SETREGS, regcache->ptid ().pid (), |
75c56d3d | 218 | (PTRACE_TYPE_ARG3) &inferior_registers, lwp); |
47221191 RE |
219 | |
220 | if (ret < 0) | |
edefbb7c | 221 | warning (_("unable to write register %d to inferior"), regno); |
47221191 RE |
222 | } |
223 | ||
224 | static void | |
56be3814 | 225 | store_regs (const struct regcache *regcache) |
47221191 | 226 | { |
ac7936df | 227 | struct gdbarch *gdbarch = regcache->arch (); |
47221191 | 228 | struct reg inferior_registers; |
75c56d3d | 229 | int lwp = regcache->ptid ().lwp (); |
47221191 RE |
230 | int ret; |
231 | int regno; | |
232 | ||
233 | ||
234 | for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++) | |
34a79281 | 235 | regcache->raw_collect (regno, (char *) &inferior_registers.r[regno]); |
47221191 | 236 | |
34a79281 SM |
237 | regcache->raw_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp); |
238 | regcache->raw_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr); | |
47221191 RE |
239 | |
240 | if (arm_apcs_32) | |
241 | { | |
34a79281 SM |
242 | regcache->raw_collect (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc); |
243 | regcache->raw_collect (ARM_PS_REGNUM, | |
244 | (char *) &inferior_registers.r_cpsr); | |
47221191 RE |
245 | } |
246 | else | |
247 | { | |
248 | unsigned pc_val; | |
249 | unsigned psr_val; | |
250 | ||
34a79281 SM |
251 | regcache->raw_collect (ARM_PC_REGNUM, (char *) &pc_val); |
252 | regcache->raw_collect (ARM_PS_REGNUM, (char *) &psr_val); | |
47221191 | 253 | |
b2cb219a UW |
254 | pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val); |
255 | psr_val ^= gdbarch_addr_bits_remove (gdbarch, psr_val); | |
47221191 RE |
256 | |
257 | inferior_registers.r_pc = pc_val | psr_val; | |
258 | } | |
259 | ||
e99b03dc | 260 | ret = ptrace (PT_SETREGS, regcache->ptid ().pid (), |
75c56d3d | 261 | (PTRACE_TYPE_ARG3) &inferior_registers, lwp); |
47221191 RE |
262 | |
263 | if (ret < 0) | |
edefbb7c | 264 | warning (_("unable to store general registers")); |
47221191 RE |
265 | } |
266 | ||
267 | static void | |
56be3814 | 268 | store_fp_register (const struct regcache *regcache, int regno) |
47221191 RE |
269 | { |
270 | struct fpreg inferior_fp_registers; | |
75c56d3d | 271 | int lwp = regcache->ptid ().lwp (); |
81b86b97 | 272 | int ret = ptrace (PT_GETFPREGS, regcache->ptid ().pid (), |
75c56d3d | 273 | (PTRACE_TYPE_ARG3) &inferior_fp_registers, lwp); |
81b86b97 | 274 | struct vfpreg &vfp = inferior_fp_registers.fpr_vfp; |
47221191 RE |
275 | |
276 | if (ret < 0) | |
277 | { | |
edefbb7c | 278 | warning (_("unable to fetch floating-point registers")); |
47221191 RE |
279 | return; |
280 | } | |
281 | ||
81b86b97 CB |
282 | struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); |
283 | if (regno == ARM_FPSCR_REGNUM && tdep->vfp_register_count != 0) | |
284 | regcache->raw_collect (ARM_FPSCR_REGNUM, (char *) &vfp.vfp_fpscr); | |
285 | else if (regno >= ARM_D0_REGNUM | |
286 | && regno <= ARM_D0_REGNUM + tdep->vfp_register_count) | |
47221191 | 287 | { |
81b86b97 CB |
288 | regcache->raw_collect (regno, |
289 | (char *) &vfp.vfp_regs[regno - ARM_D0_REGNUM]); | |
47221191 | 290 | } |
81b86b97 CB |
291 | else |
292 | warning (_("Invalid register number.")); | |
47221191 | 293 | |
e99b03dc | 294 | ret = ptrace (PT_SETFPREGS, regcache->ptid ().pid (), |
75c56d3d | 295 | (PTRACE_TYPE_ARG3) &inferior_fp_registers, lwp); |
47221191 RE |
296 | |
297 | if (ret < 0) | |
edefbb7c | 298 | warning (_("unable to write register %d to inferior"), regno); |
47221191 RE |
299 | } |
300 | ||
301 | static void | |
56be3814 | 302 | store_fp_regs (const struct regcache *regcache) |
47221191 | 303 | { |
81b86b97 | 304 | struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); |
75c56d3d | 305 | int lwp = regcache->ptid ().lwp (); |
81b86b97 CB |
306 | if (tdep->vfp_register_count == 0) |
307 | return; | |
47221191 | 308 | |
81b86b97 CB |
309 | struct fpreg fpregs; |
310 | for (int regno = 0; regno <= tdep->vfp_register_count; regno++) | |
34a79281 | 311 | regcache->raw_collect |
81b86b97 | 312 | (regno + ARM_D0_REGNUM, (char *) &fpregs.fpr_vfp.vfp_regs[regno]); |
47221191 | 313 | |
81b86b97 CB |
314 | regcache->raw_collect (ARM_FPSCR_REGNUM, |
315 | (char *) &fpregs.fpr_vfp.vfp_fpscr); | |
47221191 | 316 | |
81b86b97 | 317 | int ret = ptrace (PT_SETFPREGS, regcache->ptid ().pid (), |
75c56d3d | 318 | (PTRACE_TYPE_ARG3) &fpregs, lwp); |
47221191 RE |
319 | |
320 | if (ret < 0) | |
edefbb7c | 321 | warning (_("unable to store floating-point registers")); |
47221191 RE |
322 | } |
323 | ||
f6ac5f3d | 324 | void |
3050c6f4 | 325 | arm_netbsd_nat_target::store_registers (struct regcache *regcache, int regno) |
47221191 RE |
326 | { |
327 | if (regno >= 0) | |
328 | { | |
329 | if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM) | |
56be3814 | 330 | store_register (regcache, regno); |
47221191 | 331 | else |
56be3814 | 332 | store_fp_register (regcache, regno); |
47221191 RE |
333 | } |
334 | else | |
335 | { | |
56be3814 UW |
336 | store_regs (regcache); |
337 | store_fp_regs (regcache); | |
47221191 | 338 | } |
e7a42bc8 FN |
339 | } |
340 | ||
81b86b97 CB |
341 | const struct target_desc * |
342 | arm_netbsd_nat_target::read_description () | |
343 | { | |
344 | int flag; | |
345 | size_t len = sizeof (flag); | |
346 | ||
347 | if (sysctlbyname("machdep.fpu_present", &flag, &len, NULL, 0) != 0 | |
348 | || !flag) | |
349 | return arm_read_description (ARM_FP_TYPE_NONE); | |
350 | ||
351 | len = sizeof(flag); | |
352 | if (sysctlbyname("machdep.neon_present", &flag, &len, NULL, 0) == 0 && flag) | |
353 | return aarch32_read_description (); | |
354 | ||
355 | return arm_read_description (ARM_FP_TYPE_VFPV3); | |
356 | } | |
357 | ||
6c265988 | 358 | void _initialize_arm_netbsd_nat (); |
3e56fc4b | 359 | void |
6c265988 | 360 | _initialize_arm_netbsd_nat () |
3e56fc4b | 361 | { |
d9f719f1 | 362 | add_inf_child_target (&the_arm_netbsd_nat_target); |
3e56fc4b | 363 | } |