]>
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" | |
81b86b97 | 34 | #include "aarch32-tdep.h" |
4de283e4 | 35 | #include "inf-ptrace.h" |
e7a42bc8 | 36 | |
f6ac5f3d PA |
37 | class arm_netbsd_nat_target final : public inf_ptrace_target |
38 | { | |
39 | public: | |
40 | /* Add our register access methods. */ | |
41 | void fetch_registers (struct regcache *, int) override; | |
42 | void store_registers (struct regcache *, int) override; | |
81b86b97 | 43 | const struct target_desc *read_description () override; |
f6ac5f3d PA |
44 | }; |
45 | ||
46 | static arm_netbsd_nat_target the_arm_netbsd_nat_target; | |
47 | ||
b34db576 | 48 | static void |
d683e2b7 | 49 | arm_supply_gregset (struct regcache *regcache, struct reg *gregset) |
b34db576 RE |
50 | { |
51 | int regno; | |
52 | CORE_ADDR r_pc; | |
53 | ||
54 | /* Integer registers. */ | |
55 | for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++) | |
73e1c03f | 56 | regcache->raw_supply (regno, (char *) &gregset->r[regno]); |
b34db576 | 57 | |
73e1c03f SM |
58 | regcache->raw_supply (ARM_SP_REGNUM, (char *) &gregset->r_sp); |
59 | regcache->raw_supply (ARM_LR_REGNUM, (char *) &gregset->r_lr); | |
b34db576 | 60 | /* This is ok: we're running native... */ |
ac7936df | 61 | r_pc = gdbarch_addr_bits_remove (regcache->arch (), gregset->r_pc); |
73e1c03f | 62 | regcache->raw_supply (ARM_PC_REGNUM, (char *) &r_pc); |
b34db576 RE |
63 | |
64 | if (arm_apcs_32) | |
73e1c03f | 65 | regcache->raw_supply (ARM_PS_REGNUM, (char *) &gregset->r_cpsr); |
b34db576 | 66 | else |
73e1c03f | 67 | regcache->raw_supply (ARM_PS_REGNUM, (char *) &gregset->r_pc); |
b34db576 RE |
68 | } |
69 | ||
70 | static void | |
81b86b97 | 71 | arm_supply_vfpregset (struct regcache *regcache, struct fpreg *fpregset) |
b34db576 | 72 | { |
81b86b97 CB |
73 | struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); |
74 | if (tdep->vfp_register_count == 0) | |
75 | return; | |
b34db576 | 76 | |
81b86b97 CB |
77 | struct vfpreg &vfp = fpregset->fpr_vfp; |
78 | for (int regno = 0; regno <= tdep->vfp_register_count; regno++) | |
79 | regcache->raw_supply (regno + ARM_D0_REGNUM, (char *) &vfp.vfp_regs[regno]); | |
b34db576 | 80 | |
81b86b97 | 81 | regcache->raw_supply (ARM_FPSCR_REGNUM, (char *) &vfp.vfp_fpscr); |
b34db576 RE |
82 | } |
83 | ||
47221191 | 84 | static void |
56be3814 | 85 | fetch_register (struct regcache *regcache, int regno) |
47221191 RE |
86 | { |
87 | struct reg inferior_registers; | |
88 | int ret; | |
89 | ||
e99b03dc | 90 | ret = ptrace (PT_GETREGS, regcache->ptid ().pid (), |
9f8e0089 | 91 | (PTRACE_TYPE_ARG3) &inferior_registers, 0); |
47221191 RE |
92 | |
93 | if (ret < 0) | |
94 | { | |
edefbb7c | 95 | warning (_("unable to fetch general register")); |
47221191 RE |
96 | return; |
97 | } | |
98 | ||
99 | switch (regno) | |
100 | { | |
101 | case ARM_SP_REGNUM: | |
73e1c03f | 102 | regcache->raw_supply (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp); |
47221191 RE |
103 | break; |
104 | ||
105 | case ARM_LR_REGNUM: | |
73e1c03f | 106 | regcache->raw_supply (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr); |
47221191 RE |
107 | break; |
108 | ||
109 | case ARM_PC_REGNUM: | |
0963b4bd | 110 | /* This is ok: we're running native... */ |
bf6ae464 | 111 | inferior_registers.r_pc = gdbarch_addr_bits_remove |
ac7936df | 112 | (regcache->arch (), |
b2cb219a | 113 | inferior_registers.r_pc); |
73e1c03f | 114 | regcache->raw_supply (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc); |
47221191 RE |
115 | break; |
116 | ||
117 | case ARM_PS_REGNUM: | |
118 | if (arm_apcs_32) | |
73e1c03f SM |
119 | regcache->raw_supply (ARM_PS_REGNUM, |
120 | (char *) &inferior_registers.r_cpsr); | |
47221191 | 121 | else |
73e1c03f SM |
122 | regcache->raw_supply (ARM_PS_REGNUM, |
123 | (char *) &inferior_registers.r_pc); | |
47221191 RE |
124 | break; |
125 | ||
126 | default: | |
73e1c03f | 127 | regcache->raw_supply (regno, (char *) &inferior_registers.r[regno]); |
47221191 RE |
128 | break; |
129 | } | |
130 | } | |
131 | ||
132 | static void | |
56be3814 | 133 | fetch_regs (struct regcache *regcache) |
e7a42bc8 FN |
134 | { |
135 | struct reg inferior_registers; | |
47221191 RE |
136 | int ret; |
137 | int regno; | |
138 | ||
e99b03dc | 139 | ret = ptrace (PT_GETREGS, regcache->ptid ().pid (), |
9f8e0089 | 140 | (PTRACE_TYPE_ARG3) &inferior_registers, 0); |
47221191 RE |
141 | |
142 | if (ret < 0) | |
143 | { | |
edefbb7c | 144 | warning (_("unable to fetch general registers")); |
47221191 RE |
145 | return; |
146 | } | |
147 | ||
56be3814 | 148 | arm_supply_gregset (regcache, &inferior_registers); |
47221191 RE |
149 | } |
150 | ||
151 | static void | |
56be3814 | 152 | fetch_fp_register (struct regcache *regcache, int regno) |
47221191 RE |
153 | { |
154 | struct fpreg inferior_fp_registers; | |
81b86b97 CB |
155 | int ret = ptrace (PT_GETFPREGS, regcache->ptid ().pid (), |
156 | (PTRACE_TYPE_ARG3) &inferior_fp_registers, 0); | |
47221191 | 157 | |
81b86b97 | 158 | struct vfpreg &vfp = inferior_fp_registers.fpr_vfp; |
47221191 RE |
159 | |
160 | if (ret < 0) | |
161 | { | |
edefbb7c | 162 | warning (_("unable to fetch floating-point register")); |
47221191 RE |
163 | return; |
164 | } | |
165 | ||
81b86b97 CB |
166 | struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); |
167 | if (regno == ARM_FPSCR_REGNUM && tdep->vfp_register_count != 0) | |
168 | regcache->raw_supply (ARM_FPSCR_REGNUM, (char *) &vfp.vfp_fpscr); | |
169 | else if (regno >= ARM_D0_REGNUM | |
170 | && regno <= ARM_D0_REGNUM + tdep->vfp_register_count) | |
47221191 | 171 | { |
81b86b97 CB |
172 | regcache->raw_supply (regno, |
173 | (char *) &vfp.vfp_regs[regno - ARM_D0_REGNUM]); | |
47221191 | 174 | } |
81b86b97 CB |
175 | else |
176 | warning (_("Invalid register number.")); | |
47221191 RE |
177 | } |
178 | ||
179 | static void | |
56be3814 | 180 | fetch_fp_regs (struct regcache *regcache) |
47221191 RE |
181 | { |
182 | struct fpreg inferior_fp_registers; | |
183 | int ret; | |
184 | int regno; | |
185 | ||
e99b03dc | 186 | ret = ptrace (PT_GETFPREGS, regcache->ptid ().pid (), |
9f8e0089 | 187 | (PTRACE_TYPE_ARG3) &inferior_fp_registers, 0); |
47221191 RE |
188 | |
189 | if (ret < 0) | |
190 | { | |
edefbb7c | 191 | warning (_("unable to fetch general registers")); |
47221191 RE |
192 | return; |
193 | } | |
194 | ||
81b86b97 | 195 | arm_supply_vfpregset (regcache, &inferior_fp_registers); |
e7a42bc8 FN |
196 | } |
197 | ||
f6ac5f3d | 198 | void |
3050c6f4 | 199 | arm_netbsd_nat_target::fetch_registers (struct regcache *regcache, int regno) |
47221191 RE |
200 | { |
201 | if (regno >= 0) | |
202 | { | |
203 | if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM) | |
56be3814 | 204 | fetch_register (regcache, regno); |
47221191 | 205 | else |
56be3814 | 206 | fetch_fp_register (regcache, regno); |
47221191 RE |
207 | } |
208 | else | |
209 | { | |
56be3814 UW |
210 | fetch_regs (regcache); |
211 | fetch_fp_regs (regcache); | |
47221191 RE |
212 | } |
213 | } | |
214 | ||
215 | ||
216 | static void | |
56be3814 | 217 | store_register (const struct regcache *regcache, int regno) |
e7a42bc8 | 218 | { |
ac7936df | 219 | struct gdbarch *gdbarch = regcache->arch (); |
e7a42bc8 | 220 | struct reg inferior_registers; |
47221191 RE |
221 | int ret; |
222 | ||
e99b03dc | 223 | ret = ptrace (PT_GETREGS, regcache->ptid ().pid (), |
9f8e0089 | 224 | (PTRACE_TYPE_ARG3) &inferior_registers, 0); |
47221191 RE |
225 | |
226 | if (ret < 0) | |
227 | { | |
edefbb7c | 228 | warning (_("unable to fetch general registers")); |
47221191 RE |
229 | return; |
230 | } | |
231 | ||
232 | switch (regno) | |
233 | { | |
234 | case ARM_SP_REGNUM: | |
34a79281 | 235 | regcache->raw_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp); |
47221191 RE |
236 | break; |
237 | ||
238 | case ARM_LR_REGNUM: | |
34a79281 | 239 | regcache->raw_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr); |
47221191 | 240 | break; |
e7a42bc8 | 241 | |
47221191 RE |
242 | case ARM_PC_REGNUM: |
243 | if (arm_apcs_32) | |
34a79281 SM |
244 | regcache->raw_collect (ARM_PC_REGNUM, |
245 | (char *) &inferior_registers.r_pc); | |
47221191 RE |
246 | else |
247 | { | |
248 | unsigned pc_val; | |
e7a42bc8 | 249 | |
34a79281 | 250 | regcache->raw_collect (ARM_PC_REGNUM, (char *) &pc_val); |
47221191 | 251 | |
b2cb219a | 252 | pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val); |
bf6ae464 | 253 | inferior_registers.r_pc ^= gdbarch_addr_bits_remove |
b2cb219a | 254 | (gdbarch, inferior_registers.r_pc); |
47221191 RE |
255 | inferior_registers.r_pc |= pc_val; |
256 | } | |
257 | break; | |
258 | ||
259 | case ARM_PS_REGNUM: | |
260 | if (arm_apcs_32) | |
34a79281 SM |
261 | regcache->raw_collect (ARM_PS_REGNUM, |
262 | (char *) &inferior_registers.r_cpsr); | |
47221191 RE |
263 | else |
264 | { | |
265 | unsigned psr_val; | |
266 | ||
34a79281 | 267 | regcache->raw_collect (ARM_PS_REGNUM, (char *) &psr_val); |
47221191 | 268 | |
b2cb219a | 269 | psr_val ^= gdbarch_addr_bits_remove (gdbarch, psr_val); |
bf6ae464 | 270 | inferior_registers.r_pc = gdbarch_addr_bits_remove |
b2cb219a | 271 | (gdbarch, inferior_registers.r_pc); |
47221191 RE |
272 | inferior_registers.r_pc |= psr_val; |
273 | } | |
274 | break; | |
275 | ||
276 | default: | |
34a79281 | 277 | regcache->raw_collect (regno, (char *) &inferior_registers.r[regno]); |
47221191 RE |
278 | break; |
279 | } | |
280 | ||
e99b03dc | 281 | ret = ptrace (PT_SETREGS, regcache->ptid ().pid (), |
9f8e0089 | 282 | (PTRACE_TYPE_ARG3) &inferior_registers, 0); |
47221191 RE |
283 | |
284 | if (ret < 0) | |
edefbb7c | 285 | warning (_("unable to write register %d to inferior"), regno); |
47221191 RE |
286 | } |
287 | ||
288 | static void | |
56be3814 | 289 | store_regs (const struct regcache *regcache) |
47221191 | 290 | { |
ac7936df | 291 | struct gdbarch *gdbarch = regcache->arch (); |
47221191 RE |
292 | struct reg inferior_registers; |
293 | int ret; | |
294 | int regno; | |
295 | ||
296 | ||
297 | for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++) | |
34a79281 | 298 | regcache->raw_collect (regno, (char *) &inferior_registers.r[regno]); |
47221191 | 299 | |
34a79281 SM |
300 | regcache->raw_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp); |
301 | regcache->raw_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr); | |
47221191 RE |
302 | |
303 | if (arm_apcs_32) | |
304 | { | |
34a79281 SM |
305 | regcache->raw_collect (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc); |
306 | regcache->raw_collect (ARM_PS_REGNUM, | |
307 | (char *) &inferior_registers.r_cpsr); | |
47221191 RE |
308 | } |
309 | else | |
310 | { | |
311 | unsigned pc_val; | |
312 | unsigned psr_val; | |
313 | ||
34a79281 SM |
314 | regcache->raw_collect (ARM_PC_REGNUM, (char *) &pc_val); |
315 | regcache->raw_collect (ARM_PS_REGNUM, (char *) &psr_val); | |
47221191 | 316 | |
b2cb219a UW |
317 | pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val); |
318 | psr_val ^= gdbarch_addr_bits_remove (gdbarch, psr_val); | |
47221191 RE |
319 | |
320 | inferior_registers.r_pc = pc_val | psr_val; | |
321 | } | |
322 | ||
e99b03dc | 323 | ret = ptrace (PT_SETREGS, regcache->ptid ().pid (), |
9f8e0089 | 324 | (PTRACE_TYPE_ARG3) &inferior_registers, 0); |
47221191 RE |
325 | |
326 | if (ret < 0) | |
edefbb7c | 327 | warning (_("unable to store general registers")); |
47221191 RE |
328 | } |
329 | ||
330 | static void | |
56be3814 | 331 | store_fp_register (const struct regcache *regcache, int regno) |
47221191 RE |
332 | { |
333 | struct fpreg inferior_fp_registers; | |
81b86b97 CB |
334 | int ret = ptrace (PT_GETFPREGS, regcache->ptid ().pid (), |
335 | (PTRACE_TYPE_ARG3) &inferior_fp_registers, 0); | |
336 | struct vfpreg &vfp = inferior_fp_registers.fpr_vfp; | |
47221191 RE |
337 | |
338 | if (ret < 0) | |
339 | { | |
edefbb7c | 340 | warning (_("unable to fetch floating-point registers")); |
47221191 RE |
341 | return; |
342 | } | |
343 | ||
81b86b97 CB |
344 | struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); |
345 | if (regno == ARM_FPSCR_REGNUM && tdep->vfp_register_count != 0) | |
346 | regcache->raw_collect (ARM_FPSCR_REGNUM, (char *) &vfp.vfp_fpscr); | |
347 | else if (regno >= ARM_D0_REGNUM | |
348 | && regno <= ARM_D0_REGNUM + tdep->vfp_register_count) | |
47221191 | 349 | { |
81b86b97 CB |
350 | regcache->raw_collect (regno, |
351 | (char *) &vfp.vfp_regs[regno - ARM_D0_REGNUM]); | |
47221191 | 352 | } |
81b86b97 CB |
353 | else |
354 | warning (_("Invalid register number.")); | |
47221191 | 355 | |
e99b03dc | 356 | ret = ptrace (PT_SETFPREGS, regcache->ptid ().pid (), |
9f8e0089 | 357 | (PTRACE_TYPE_ARG3) &inferior_fp_registers, 0); |
47221191 RE |
358 | |
359 | if (ret < 0) | |
edefbb7c | 360 | warning (_("unable to write register %d to inferior"), regno); |
47221191 RE |
361 | } |
362 | ||
363 | static void | |
56be3814 | 364 | store_fp_regs (const struct regcache *regcache) |
47221191 | 365 | { |
81b86b97 CB |
366 | struct gdbarch_tdep *tdep = gdbarch_tdep (regcache->arch ()); |
367 | if (tdep->vfp_register_count == 0) | |
368 | return; | |
47221191 | 369 | |
81b86b97 CB |
370 | struct fpreg fpregs; |
371 | for (int regno = 0; regno <= tdep->vfp_register_count; regno++) | |
34a79281 | 372 | regcache->raw_collect |
81b86b97 | 373 | (regno + ARM_D0_REGNUM, (char *) &fpregs.fpr_vfp.vfp_regs[regno]); |
47221191 | 374 | |
81b86b97 CB |
375 | regcache->raw_collect (ARM_FPSCR_REGNUM, |
376 | (char *) &fpregs.fpr_vfp.vfp_fpscr); | |
47221191 | 377 | |
81b86b97 CB |
378 | int ret = ptrace (PT_SETFPREGS, regcache->ptid ().pid (), |
379 | (PTRACE_TYPE_ARG3) &fpregs, 0); | |
47221191 RE |
380 | |
381 | if (ret < 0) | |
edefbb7c | 382 | warning (_("unable to store floating-point registers")); |
47221191 RE |
383 | } |
384 | ||
f6ac5f3d | 385 | void |
3050c6f4 | 386 | arm_netbsd_nat_target::store_registers (struct regcache *regcache, int regno) |
47221191 RE |
387 | { |
388 | if (regno >= 0) | |
389 | { | |
390 | if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM) | |
56be3814 | 391 | store_register (regcache, regno); |
47221191 | 392 | else |
56be3814 | 393 | store_fp_register (regcache, regno); |
47221191 RE |
394 | } |
395 | else | |
396 | { | |
56be3814 UW |
397 | store_regs (regcache); |
398 | store_fp_regs (regcache); | |
47221191 | 399 | } |
e7a42bc8 FN |
400 | } |
401 | ||
81b86b97 CB |
402 | const struct target_desc * |
403 | arm_netbsd_nat_target::read_description () | |
404 | { | |
405 | int flag; | |
406 | size_t len = sizeof (flag); | |
407 | ||
408 | if (sysctlbyname("machdep.fpu_present", &flag, &len, NULL, 0) != 0 | |
409 | || !flag) | |
410 | return arm_read_description (ARM_FP_TYPE_NONE); | |
411 | ||
412 | len = sizeof(flag); | |
413 | if (sysctlbyname("machdep.neon_present", &flag, &len, NULL, 0) == 0 && flag) | |
414 | return aarch32_read_description (); | |
415 | ||
416 | return arm_read_description (ARM_FP_TYPE_VFPV3); | |
417 | } | |
418 | ||
b34db576 | 419 | static void |
9eefc95f | 420 | fetch_elfcore_registers (struct regcache *regcache, |
0cac9354 | 421 | gdb_byte *core_reg_sect, unsigned core_reg_size, |
b34db576 RE |
422 | int which, CORE_ADDR ignore) |
423 | { | |
424 | struct reg gregset; | |
425 | struct fpreg fparegset; | |
e7a42bc8 | 426 | |
b34db576 RE |
427 | switch (which) |
428 | { | |
429 | case 0: /* Integer registers. */ | |
430 | if (core_reg_size != sizeof (struct reg)) | |
edefbb7c | 431 | warning (_("wrong size of register set in core file")); |
b34db576 RE |
432 | else |
433 | { | |
434 | /* The memcpy may be unnecessary, but we can't really be sure | |
435 | of the alignment of the data in the core file. */ | |
436 | memcpy (&gregset, core_reg_sect, sizeof (gregset)); | |
9eefc95f | 437 | arm_supply_gregset (regcache, &gregset); |
b34db576 RE |
438 | } |
439 | break; | |
440 | ||
441 | case 2: | |
81b86b97 CB |
442 | /* cbiesinger/2020-02-12 -- as far as I can tell, ARM/NetBSD does |
443 | not write any floating point registers into the core file (tested | |
444 | with NetBSD 9.1_RC1). When it does, this block will need to read them, | |
445 | and the arm-netbsd gdbarch will need a core_read_description function | |
446 | to return the right description for them. */ | |
b34db576 | 447 | break; |
3e56fc4b | 448 | |
b34db576 RE |
449 | default: |
450 | /* Don't know what kind of register request this is; just ignore it. */ | |
451 | break; | |
452 | } | |
e7a42bc8 FN |
453 | } |
454 | ||
b34db576 RE |
455 | static struct core_fns arm_netbsd_elfcore_fns = |
456 | { | |
405feb71 | 457 | bfd_target_elf_flavour, /* core_flavour. */ |
b34db576 RE |
458 | default_check_format, /* check_format. */ |
459 | default_core_sniffer, /* core_sniffer. */ | |
460 | fetch_elfcore_registers, /* core_read_registers. */ | |
461 | NULL | |
462 | }; | |
463 | ||
6c265988 | 464 | void _initialize_arm_netbsd_nat (); |
3e56fc4b | 465 | void |
6c265988 | 466 | _initialize_arm_netbsd_nat () |
3e56fc4b | 467 | { |
d9f719f1 | 468 | add_inf_child_target (&the_arm_netbsd_nat_target); |
2b73aeb1 | 469 | |
00e32a35 | 470 | deprecated_add_core_fns (&arm_netbsd_elfcore_fns); |
3e56fc4b | 471 | } |