Commit | Line | Data |
---|---|---|
e7a42bc8 | 1 | /* Native-dependent code for BSD Unix running on ARM's, for GDB. |
9f8e0089 | 2 | |
b811d2c2 | 3 | Copyright (C) 1988-2020 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" | |
8dd8e1c7 | 34 | #include "arm-nbsd-tdep.h" |
81b86b97 | 35 | #include "aarch32-tdep.h" |
4de283e4 | 36 | #include "inf-ptrace.h" |
e7a42bc8 | 37 | |
f6ac5f3d PA |
38 | class arm_netbsd_nat_target final : public inf_ptrace_target |
39 | { | |
40 | public: | |
41 | /* Add our register access methods. */ | |
42 | void fetch_registers (struct regcache *, int) override; | |
43 | void store_registers (struct regcache *, int) override; | |
81b86b97 | 44 | const struct target_desc *read_description () override; |
f6ac5f3d PA |
45 | }; |
46 | ||
47 | static arm_netbsd_nat_target the_arm_netbsd_nat_target; | |
48 | ||
b34db576 | 49 | static void |
81b86b97 | 50 | arm_supply_vfpregset (struct regcache *regcache, struct fpreg *fpregset) |
b34db576 | 51 | { |
81b86b97 CB |
52 | struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); |
53 | if (tdep->vfp_register_count == 0) | |
54 | return; | |
b34db576 | 55 | |
81b86b97 CB |
56 | struct vfpreg &vfp = fpregset->fpr_vfp; |
57 | for (int regno = 0; regno <= tdep->vfp_register_count; regno++) | |
58 | regcache->raw_supply (regno + ARM_D0_REGNUM, (char *) &vfp.vfp_regs[regno]); | |
b34db576 | 59 | |
81b86b97 | 60 | regcache->raw_supply (ARM_FPSCR_REGNUM, (char *) &vfp.vfp_fpscr); |
b34db576 RE |
61 | } |
62 | ||
47221191 | 63 | static void |
56be3814 | 64 | fetch_register (struct regcache *regcache, int regno) |
47221191 RE |
65 | { |
66 | struct reg inferior_registers; | |
67 | int ret; | |
68 | ||
e99b03dc | 69 | ret = ptrace (PT_GETREGS, regcache->ptid ().pid (), |
9f8e0089 | 70 | (PTRACE_TYPE_ARG3) &inferior_registers, 0); |
47221191 RE |
71 | |
72 | if (ret < 0) | |
73 | { | |
edefbb7c | 74 | warning (_("unable to fetch general register")); |
47221191 RE |
75 | return; |
76 | } | |
8dd8e1c7 CB |
77 | arm_nbsd_supply_gregset (nullptr, regcache, regno, &inferior_registers, |
78 | sizeof (inferior_registers)); | |
47221191 RE |
79 | } |
80 | ||
81 | static void | |
56be3814 | 82 | fetch_fp_register (struct regcache *regcache, int regno) |
47221191 RE |
83 | { |
84 | struct fpreg inferior_fp_registers; | |
81b86b97 CB |
85 | int ret = ptrace (PT_GETFPREGS, regcache->ptid ().pid (), |
86 | (PTRACE_TYPE_ARG3) &inferior_fp_registers, 0); | |
47221191 | 87 | |
81b86b97 | 88 | struct vfpreg &vfp = inferior_fp_registers.fpr_vfp; |
47221191 RE |
89 | |
90 | if (ret < 0) | |
91 | { | |
edefbb7c | 92 | warning (_("unable to fetch floating-point register")); |
47221191 RE |
93 | return; |
94 | } | |
95 | ||
81b86b97 CB |
96 | struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); |
97 | if (regno == ARM_FPSCR_REGNUM && tdep->vfp_register_count != 0) | |
98 | regcache->raw_supply (ARM_FPSCR_REGNUM, (char *) &vfp.vfp_fpscr); | |
99 | else if (regno >= ARM_D0_REGNUM | |
100 | && regno <= ARM_D0_REGNUM + tdep->vfp_register_count) | |
47221191 | 101 | { |
81b86b97 CB |
102 | regcache->raw_supply (regno, |
103 | (char *) &vfp.vfp_regs[regno - ARM_D0_REGNUM]); | |
47221191 | 104 | } |
81b86b97 CB |
105 | else |
106 | warning (_("Invalid register number.")); | |
47221191 RE |
107 | } |
108 | ||
109 | static void | |
56be3814 | 110 | fetch_fp_regs (struct regcache *regcache) |
47221191 RE |
111 | { |
112 | struct fpreg inferior_fp_registers; | |
113 | int ret; | |
114 | int regno; | |
115 | ||
e99b03dc | 116 | ret = ptrace (PT_GETFPREGS, regcache->ptid ().pid (), |
9f8e0089 | 117 | (PTRACE_TYPE_ARG3) &inferior_fp_registers, 0); |
47221191 RE |
118 | |
119 | if (ret < 0) | |
120 | { | |
edefbb7c | 121 | warning (_("unable to fetch general registers")); |
47221191 RE |
122 | return; |
123 | } | |
124 | ||
81b86b97 | 125 | arm_supply_vfpregset (regcache, &inferior_fp_registers); |
e7a42bc8 FN |
126 | } |
127 | ||
f6ac5f3d | 128 | void |
3050c6f4 | 129 | arm_netbsd_nat_target::fetch_registers (struct regcache *regcache, int regno) |
47221191 RE |
130 | { |
131 | if (regno >= 0) | |
132 | { | |
133 | if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM) | |
56be3814 | 134 | fetch_register (regcache, regno); |
47221191 | 135 | else |
56be3814 | 136 | fetch_fp_register (regcache, regno); |
47221191 RE |
137 | } |
138 | else | |
139 | { | |
8dd8e1c7 | 140 | fetch_register (regcache, -1); |
56be3814 | 141 | fetch_fp_regs (regcache); |
47221191 RE |
142 | } |
143 | } | |
144 | ||
145 | ||
146 | static void | |
56be3814 | 147 | store_register (const struct regcache *regcache, int regno) |
e7a42bc8 | 148 | { |
ac7936df | 149 | struct gdbarch *gdbarch = regcache->arch (); |
e7a42bc8 | 150 | struct reg inferior_registers; |
47221191 RE |
151 | int ret; |
152 | ||
e99b03dc | 153 | ret = ptrace (PT_GETREGS, regcache->ptid ().pid (), |
9f8e0089 | 154 | (PTRACE_TYPE_ARG3) &inferior_registers, 0); |
47221191 RE |
155 | |
156 | if (ret < 0) | |
157 | { | |
edefbb7c | 158 | warning (_("unable to fetch general registers")); |
47221191 RE |
159 | return; |
160 | } | |
161 | ||
162 | switch (regno) | |
163 | { | |
164 | case ARM_SP_REGNUM: | |
34a79281 | 165 | regcache->raw_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp); |
47221191 RE |
166 | break; |
167 | ||
168 | case ARM_LR_REGNUM: | |
34a79281 | 169 | regcache->raw_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr); |
47221191 | 170 | break; |
e7a42bc8 | 171 | |
47221191 RE |
172 | case ARM_PC_REGNUM: |
173 | if (arm_apcs_32) | |
34a79281 SM |
174 | regcache->raw_collect (ARM_PC_REGNUM, |
175 | (char *) &inferior_registers.r_pc); | |
47221191 RE |
176 | else |
177 | { | |
178 | unsigned pc_val; | |
e7a42bc8 | 179 | |
34a79281 | 180 | regcache->raw_collect (ARM_PC_REGNUM, (char *) &pc_val); |
47221191 | 181 | |
b2cb219a | 182 | pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val); |
bf6ae464 | 183 | inferior_registers.r_pc ^= gdbarch_addr_bits_remove |
b2cb219a | 184 | (gdbarch, inferior_registers.r_pc); |
47221191 RE |
185 | inferior_registers.r_pc |= pc_val; |
186 | } | |
187 | break; | |
188 | ||
189 | case ARM_PS_REGNUM: | |
190 | if (arm_apcs_32) | |
34a79281 SM |
191 | regcache->raw_collect (ARM_PS_REGNUM, |
192 | (char *) &inferior_registers.r_cpsr); | |
47221191 RE |
193 | else |
194 | { | |
195 | unsigned psr_val; | |
196 | ||
34a79281 | 197 | regcache->raw_collect (ARM_PS_REGNUM, (char *) &psr_val); |
47221191 | 198 | |
b2cb219a | 199 | psr_val ^= gdbarch_addr_bits_remove (gdbarch, psr_val); |
bf6ae464 | 200 | inferior_registers.r_pc = gdbarch_addr_bits_remove |
b2cb219a | 201 | (gdbarch, inferior_registers.r_pc); |
47221191 RE |
202 | inferior_registers.r_pc |= psr_val; |
203 | } | |
204 | break; | |
205 | ||
206 | default: | |
34a79281 | 207 | regcache->raw_collect (regno, (char *) &inferior_registers.r[regno]); |
47221191 RE |
208 | break; |
209 | } | |
210 | ||
e99b03dc | 211 | ret = ptrace (PT_SETREGS, regcache->ptid ().pid (), |
9f8e0089 | 212 | (PTRACE_TYPE_ARG3) &inferior_registers, 0); |
47221191 RE |
213 | |
214 | if (ret < 0) | |
edefbb7c | 215 | warning (_("unable to write register %d to inferior"), regno); |
47221191 RE |
216 | } |
217 | ||
218 | static void | |
56be3814 | 219 | store_regs (const struct regcache *regcache) |
47221191 | 220 | { |
ac7936df | 221 | struct gdbarch *gdbarch = regcache->arch (); |
47221191 RE |
222 | struct reg inferior_registers; |
223 | int ret; | |
224 | int regno; | |
225 | ||
226 | ||
227 | for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++) | |
34a79281 | 228 | regcache->raw_collect (regno, (char *) &inferior_registers.r[regno]); |
47221191 | 229 | |
34a79281 SM |
230 | regcache->raw_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp); |
231 | regcache->raw_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr); | |
47221191 RE |
232 | |
233 | if (arm_apcs_32) | |
234 | { | |
34a79281 SM |
235 | regcache->raw_collect (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc); |
236 | regcache->raw_collect (ARM_PS_REGNUM, | |
237 | (char *) &inferior_registers.r_cpsr); | |
47221191 RE |
238 | } |
239 | else | |
240 | { | |
241 | unsigned pc_val; | |
242 | unsigned psr_val; | |
243 | ||
34a79281 SM |
244 | regcache->raw_collect (ARM_PC_REGNUM, (char *) &pc_val); |
245 | regcache->raw_collect (ARM_PS_REGNUM, (char *) &psr_val); | |
47221191 | 246 | |
b2cb219a UW |
247 | pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val); |
248 | psr_val ^= gdbarch_addr_bits_remove (gdbarch, psr_val); | |
47221191 RE |
249 | |
250 | inferior_registers.r_pc = pc_val | psr_val; | |
251 | } | |
252 | ||
e99b03dc | 253 | ret = ptrace (PT_SETREGS, regcache->ptid ().pid (), |
9f8e0089 | 254 | (PTRACE_TYPE_ARG3) &inferior_registers, 0); |
47221191 RE |
255 | |
256 | if (ret < 0) | |
edefbb7c | 257 | warning (_("unable to store general registers")); |
47221191 RE |
258 | } |
259 | ||
260 | static void | |
56be3814 | 261 | store_fp_register (const struct regcache *regcache, int regno) |
47221191 RE |
262 | { |
263 | struct fpreg inferior_fp_registers; | |
81b86b97 CB |
264 | int ret = ptrace (PT_GETFPREGS, regcache->ptid ().pid (), |
265 | (PTRACE_TYPE_ARG3) &inferior_fp_registers, 0); | |
266 | struct vfpreg &vfp = inferior_fp_registers.fpr_vfp; | |
47221191 RE |
267 | |
268 | if (ret < 0) | |
269 | { | |
edefbb7c | 270 | warning (_("unable to fetch floating-point registers")); |
47221191 RE |
271 | return; |
272 | } | |
273 | ||
81b86b97 CB |
274 | struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); |
275 | if (regno == ARM_FPSCR_REGNUM && tdep->vfp_register_count != 0) | |
276 | regcache->raw_collect (ARM_FPSCR_REGNUM, (char *) &vfp.vfp_fpscr); | |
277 | else if (regno >= ARM_D0_REGNUM | |
278 | && regno <= ARM_D0_REGNUM + tdep->vfp_register_count) | |
47221191 | 279 | { |
81b86b97 CB |
280 | regcache->raw_collect (regno, |
281 | (char *) &vfp.vfp_regs[regno - ARM_D0_REGNUM]); | |
47221191 | 282 | } |
81b86b97 CB |
283 | else |
284 | warning (_("Invalid register number.")); | |
47221191 | 285 | |
e99b03dc | 286 | ret = ptrace (PT_SETFPREGS, regcache->ptid ().pid (), |
9f8e0089 | 287 | (PTRACE_TYPE_ARG3) &inferior_fp_registers, 0); |
47221191 RE |
288 | |
289 | if (ret < 0) | |
edefbb7c | 290 | warning (_("unable to write register %d to inferior"), regno); |
47221191 RE |
291 | } |
292 | ||
293 | static void | |
56be3814 | 294 | store_fp_regs (const struct regcache *regcache) |
47221191 | 295 | { |
81b86b97 CB |
296 | struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); |
297 | if (tdep->vfp_register_count == 0) | |
298 | return; | |
47221191 | 299 | |
81b86b97 CB |
300 | struct fpreg fpregs; |
301 | for (int regno = 0; regno <= tdep->vfp_register_count; regno++) | |
34a79281 | 302 | regcache->raw_collect |
81b86b97 | 303 | (regno + ARM_D0_REGNUM, (char *) &fpregs.fpr_vfp.vfp_regs[regno]); |
47221191 | 304 | |
81b86b97 CB |
305 | regcache->raw_collect (ARM_FPSCR_REGNUM, |
306 | (char *) &fpregs.fpr_vfp.vfp_fpscr); | |
47221191 | 307 | |
81b86b97 CB |
308 | int ret = ptrace (PT_SETFPREGS, regcache->ptid ().pid (), |
309 | (PTRACE_TYPE_ARG3) &fpregs, 0); | |
47221191 RE |
310 | |
311 | if (ret < 0) | |
edefbb7c | 312 | warning (_("unable to store floating-point registers")); |
47221191 RE |
313 | } |
314 | ||
f6ac5f3d | 315 | void |
3050c6f4 | 316 | arm_netbsd_nat_target::store_registers (struct regcache *regcache, int regno) |
47221191 RE |
317 | { |
318 | if (regno >= 0) | |
319 | { | |
320 | if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM) | |
56be3814 | 321 | store_register (regcache, regno); |
47221191 | 322 | else |
56be3814 | 323 | store_fp_register (regcache, regno); |
47221191 RE |
324 | } |
325 | else | |
326 | { | |
56be3814 UW |
327 | store_regs (regcache); |
328 | store_fp_regs (regcache); | |
47221191 | 329 | } |
e7a42bc8 FN |
330 | } |
331 | ||
81b86b97 CB |
332 | const struct target_desc * |
333 | arm_netbsd_nat_target::read_description () | |
334 | { | |
335 | int flag; | |
336 | size_t len = sizeof (flag); | |
337 | ||
338 | if (sysctlbyname("machdep.fpu_present", &flag, &len, NULL, 0) != 0 | |
339 | || !flag) | |
340 | return arm_read_description (ARM_FP_TYPE_NONE); | |
341 | ||
342 | len = sizeof(flag); | |
343 | if (sysctlbyname("machdep.neon_present", &flag, &len, NULL, 0) == 0 && flag) | |
344 | return aarch32_read_description (); | |
345 | ||
346 | return arm_read_description (ARM_FP_TYPE_VFPV3); | |
347 | } | |
348 | ||
6c265988 | 349 | void _initialize_arm_netbsd_nat (); |
3e56fc4b | 350 | void |
6c265988 | 351 | _initialize_arm_netbsd_nat () |
3e56fc4b | 352 | { |
d9f719f1 | 353 | add_inf_child_target (&the_arm_netbsd_nat_target); |
3e56fc4b | 354 | } |