1/* Native-dependent code for BSD Unix running on ARM's, for GDB.
2
3   Copyright (C) 1988, 1989, 1991, 1992, 1994, 1996, 1999, 2002, 2004, 2007
4   Free Software Foundation, Inc.
5
6   This file is part of GDB.
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21#include "defs.h"
22#include "gdbcore.h"
23#include "inferior.h"
24#include "regcache.h"
25#include "target.h"
26
27#include "gdb_string.h"
28#include <sys/types.h>
29#include <sys/ptrace.h>
30#include <machine/reg.h>
31#include <machine/frame.h>
32
33#include "arm-tdep.h"
34#include "inf-ptrace.h"
35
36extern int arm_apcs_32;
37
38static void
39arm_supply_gregset (struct regcache *regcache, struct reg *gregset)
40{
41  int regno;
42  CORE_ADDR r_pc;
43
44  /* Integer registers.  */
45  for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
46    regcache_raw_supply (regcache, regno, (char *) &gregset->r[regno]);
47
48  regcache_raw_supply (regcache, ARM_SP_REGNUM,
49		       (char *) &gregset->r_sp);
50  regcache_raw_supply (regcache, ARM_LR_REGNUM,
51		       (char *) &gregset->r_lr);
52  /* This is ok: we're running native...  */
53  r_pc = gdbarch_addr_bits_remove (current_gdbarch, gregset->r_pc);
54  regcache_raw_supply (regcache, ARM_PC_REGNUM, (char *) &r_pc);
55
56  if (arm_apcs_32)
57    regcache_raw_supply (regcache, ARM_PS_REGNUM,
58			 (char *) &gregset->r_cpsr);
59  else
60    regcache_raw_supply (regcache, ARM_PS_REGNUM,
61			 (char *) &gregset->r_pc);
62}
63
64static void
65arm_supply_fparegset (struct regcache *regcache, struct fpreg *fparegset)
66{
67  int regno;
68
69  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
70    regcache_raw_supply (regcache, regno,
71			 (char *) &fparegset->fpr[regno - ARM_F0_REGNUM]);
72
73  regcache_raw_supply (regcache, ARM_FPS_REGNUM,
74		       (char *) &fparegset->fpr_fpsr);
75}
76
77static void
78fetch_register (struct regcache *regcache, int regno)
79{
80  struct reg inferior_registers;
81  int ret;
82
83  ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
84		(PTRACE_TYPE_ARG3) &inferior_registers, 0);
85
86  if (ret < 0)
87    {
88      warning (_("unable to fetch general register"));
89      return;
90    }
91
92  switch (regno)
93    {
94    case ARM_SP_REGNUM:
95      regcache_raw_supply (regcache, ARM_SP_REGNUM,
96			   (char *) &inferior_registers.r_sp);
97      break;
98
99    case ARM_LR_REGNUM:
100      regcache_raw_supply (regcache, ARM_LR_REGNUM,
101			   (char *) &inferior_registers.r_lr);
102      break;
103
104    case ARM_PC_REGNUM:
105      /* This is ok: we're running native... */
106      inferior_registers.r_pc = gdbarch_addr_bits_remove
107				  (current_gdbarch, inferior_registers.r_pc);
108      regcache_raw_supply (regcache, ARM_PC_REGNUM,
109			   (char *) &inferior_registers.r_pc);
110      break;
111
112    case ARM_PS_REGNUM:
113      if (arm_apcs_32)
114	regcache_raw_supply (regcache, ARM_PS_REGNUM,
115			     (char *) &inferior_registers.r_cpsr);
116      else
117	regcache_raw_supply (regcache, ARM_PS_REGNUM,
118			     (char *) &inferior_registers.r_pc);
119      break;
120
121    default:
122      regcache_raw_supply (regcache, regno,
123			   (char *) &inferior_registers.r[regno]);
124      break;
125    }
126}
127
128static void
129fetch_regs (struct regcache *regcache)
130{
131  struct reg inferior_registers;
132  int ret;
133  int regno;
134
135  ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
136		(PTRACE_TYPE_ARG3) &inferior_registers, 0);
137
138  if (ret < 0)
139    {
140      warning (_("unable to fetch general registers"));
141      return;
142    }
143
144  arm_supply_gregset (regcache, &inferior_registers);
145}
146
147static void
148fetch_fp_register (struct regcache *regcache, int regno)
149{
150  struct fpreg inferior_fp_registers;
151  int ret;
152
153  ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
154		(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
155
156  if (ret < 0)
157    {
158      warning (_("unable to fetch floating-point register"));
159      return;
160    }
161
162  switch (regno)
163    {
164    case ARM_FPS_REGNUM:
165      regcache_raw_supply (regcache, ARM_FPS_REGNUM,
166			   (char *) &inferior_fp_registers.fpr_fpsr);
167      break;
168
169    default:
170      regcache_raw_supply (regcache, regno,
171			   (char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
172      break;
173    }
174}
175
176static void
177fetch_fp_regs (struct regcache *regcache)
178{
179  struct fpreg inferior_fp_registers;
180  int ret;
181  int regno;
182
183  ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
184		(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
185
186  if (ret < 0)
187    {
188      warning (_("unable to fetch general registers"));
189      return;
190    }
191
192  arm_supply_fparegset (regcache, &inferior_fp_registers);
193}
194
195static void
196armnbsd_fetch_registers (struct regcache *regcache, int regno)
197{
198  if (regno >= 0)
199    {
200      if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
201	fetch_register (regcache, regno);
202      else
203	fetch_fp_register (regcache, regno);
204    }
205  else
206    {
207      fetch_regs (regcache);
208      fetch_fp_regs (regcache);
209    }
210}
211
212
213static void
214store_register (const struct regcache *regcache, int regno)
215{
216  struct reg inferior_registers;
217  int ret;
218
219  ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
220		(PTRACE_TYPE_ARG3) &inferior_registers, 0);
221
222  if (ret < 0)
223    {
224      warning (_("unable to fetch general registers"));
225      return;
226    }
227
228  switch (regno)
229    {
230    case ARM_SP_REGNUM:
231      regcache_raw_collect (regcache, ARM_SP_REGNUM,
232			    (char *) &inferior_registers.r_sp);
233      break;
234
235    case ARM_LR_REGNUM:
236      regcache_raw_collect (regcache, ARM_LR_REGNUM,
237			    (char *) &inferior_registers.r_lr);
238      break;
239
240    case ARM_PC_REGNUM:
241      if (arm_apcs_32)
242	regcache_raw_collect (regcache, ARM_PC_REGNUM,
243			      (char *) &inferior_registers.r_pc);
244      else
245	{
246	  unsigned pc_val;
247
248	  regcache_raw_collect (regcache, ARM_PC_REGNUM,
249				(char *) &pc_val);
250
251	  pc_val = gdbarch_addr_bits_remove (current_gdbarch, pc_val);
252	  inferior_registers.r_pc ^= gdbarch_addr_bits_remove
253				       (current_gdbarch,
254					inferior_registers.r_pc);
255	  inferior_registers.r_pc |= pc_val;
256	}
257      break;
258
259    case ARM_PS_REGNUM:
260      if (arm_apcs_32)
261	regcache_raw_collect (regcache, ARM_PS_REGNUM,
262			      (char *) &inferior_registers.r_cpsr);
263      else
264	{
265	  unsigned psr_val;
266
267	  regcache_raw_collect (regcache, ARM_PS_REGNUM,
268				(char *) &psr_val);
269
270	  psr_val ^= gdbarch_addr_bits_remove (current_gdbarch, psr_val);
271	  inferior_registers.r_pc = gdbarch_addr_bits_remove
272				      (current_gdbarch,
273				       inferior_registers.r_pc);
274	  inferior_registers.r_pc |= psr_val;
275	}
276      break;
277
278    default:
279      regcache_raw_collect (regcache, regno,
280			    (char *) &inferior_registers.r[regno]);
281      break;
282    }
283
284  ret = ptrace (PT_SETREGS, PIDGET (inferior_ptid),
285		(PTRACE_TYPE_ARG3) &inferior_registers, 0);
286
287  if (ret < 0)
288    warning (_("unable to write register %d to inferior"), regno);
289}
290
291static void
292store_regs (const struct regcache *regcache)
293{
294  struct reg inferior_registers;
295  int ret;
296  int regno;
297
298
299  for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
300    regcache_raw_collect (regcache, regno,
301			  (char *) &inferior_registers.r[regno]);
302
303  regcache_raw_collect (regcache, ARM_SP_REGNUM,
304			(char *) &inferior_registers.r_sp);
305  regcache_raw_collect (regcache, ARM_LR_REGNUM,
306			(char *) &inferior_registers.r_lr);
307
308  if (arm_apcs_32)
309    {
310      regcache_raw_collect (regcache, ARM_PC_REGNUM,
311			    (char *) &inferior_registers.r_pc);
312      regcache_raw_collect (regcache, ARM_PS_REGNUM,
313			    (char *) &inferior_registers.r_cpsr);
314    }
315  else
316    {
317      unsigned pc_val;
318      unsigned psr_val;
319
320      regcache_raw_collect (regcache, ARM_PC_REGNUM,
321			    (char *) &pc_val);
322      regcache_raw_collect (regcache, ARM_PS_REGNUM,
323			    (char *) &psr_val);
324
325      pc_val = gdbarch_addr_bits_remove (current_gdbarch, pc_val);
326      psr_val ^= gdbarch_addr_bits_remove (current_gdbarch, psr_val);
327
328      inferior_registers.r_pc = pc_val | psr_val;
329    }
330
331  ret = ptrace (PT_SETREGS, PIDGET (inferior_ptid),
332		(PTRACE_TYPE_ARG3) &inferior_registers, 0);
333
334  if (ret < 0)
335    warning (_("unable to store general registers"));
336}
337
338static void
339store_fp_register (const struct regcache *regcache, int regno)
340{
341  struct fpreg inferior_fp_registers;
342  int ret;
343
344  ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
345		(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
346
347  if (ret < 0)
348    {
349      warning (_("unable to fetch floating-point registers"));
350      return;
351    }
352
353  switch (regno)
354    {
355    case ARM_FPS_REGNUM:
356      regcache_raw_collect (regcache, ARM_FPS_REGNUM,
357			    (char *) &inferior_fp_registers.fpr_fpsr);
358      break;
359
360    default:
361      regcache_raw_collect (regcache, regno,
362			    (char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
363      break;
364    }
365
366  ret = ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
367		(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
368
369  if (ret < 0)
370    warning (_("unable to write register %d to inferior"), regno);
371}
372
373static void
374store_fp_regs (const struct regcache *regcache)
375{
376  struct fpreg inferior_fp_registers;
377  int ret;
378  int regno;
379
380
381  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
382    regcache_raw_collect (regcache, regno,
383			  (char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
384
385  regcache_raw_collect (regcache, ARM_FPS_REGNUM,
386			(char *) &inferior_fp_registers.fpr_fpsr);
387
388  ret = ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
389		(PTRACE_TYPE_ARG3) &inferior_fp_registers, 0);
390
391  if (ret < 0)
392    warning (_("unable to store floating-point registers"));
393}
394
395static void
396armnbsd_store_registers (struct regcache *regcache, int regno)
397{
398  if (regno >= 0)
399    {
400      if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
401	store_register (regcache, regno);
402      else
403	store_fp_register (regcache, regno);
404    }
405  else
406    {
407      store_regs (regcache);
408      store_fp_regs (regcache);
409    }
410}
411
412struct md_core
413{
414  struct reg intreg;
415  struct fpreg freg;
416};
417
418static void
419fetch_core_registers (struct regcache *regcache,
420		      char *core_reg_sect, unsigned core_reg_size,
421		      int which, CORE_ADDR ignore)
422{
423  struct md_core *core_reg = (struct md_core *) core_reg_sect;
424  int regno;
425  CORE_ADDR r_pc;
426
427  arm_supply_gregset (regcache, &core_reg->intreg);
428  arm_supply_fparegset (regcache, &core_reg->freg);
429}
430
431static void
432fetch_elfcore_registers (struct regcache *regcache,
433			 char *core_reg_sect, unsigned core_reg_size,
434			 int which, CORE_ADDR ignore)
435{
436  struct reg gregset;
437  struct fpreg fparegset;
438
439  switch (which)
440    {
441    case 0:	/* Integer registers.  */
442      if (core_reg_size != sizeof (struct reg))
443	warning (_("wrong size of register set in core file"));
444      else
445	{
446	  /* The memcpy may be unnecessary, but we can't really be sure
447	     of the alignment of the data in the core file.  */
448	  memcpy (&gregset, core_reg_sect, sizeof (gregset));
449	  arm_supply_gregset (regcache, &gregset);
450	}
451      break;
452
453    case 2:
454      if (core_reg_size != sizeof (struct fpreg))
455	warning (_("wrong size of FPA register set in core file"));
456      else
457	{
458	  /* The memcpy may be unnecessary, but we can't really be sure
459	     of the alignment of the data in the core file.  */
460	  memcpy (&fparegset, core_reg_sect, sizeof (fparegset));
461	  arm_supply_fparegset (regcache, &fparegset);
462	}
463      break;
464
465    default:
466      /* Don't know what kind of register request this is; just ignore it.  */
467      break;
468    }
469}
470
471static struct core_fns arm_netbsd_core_fns =
472{
473  bfd_target_unknown_flavour,		/* core_flovour.  */
474  default_check_format,			/* check_format.  */
475  default_core_sniffer,			/* core_sniffer.  */
476  fetch_core_registers,			/* core_read_registers.  */
477  NULL
478};
479
480static struct core_fns arm_netbsd_elfcore_fns =
481{
482  bfd_target_elf_flavour,		/* core_flovour.  */
483  default_check_format,			/* check_format.  */
484  default_core_sniffer,			/* core_sniffer.  */
485  fetch_elfcore_registers,		/* core_read_registers.  */
486  NULL
487};
488
489void
490_initialize_arm_netbsd_nat (void)
491{
492  struct target_ops *t;
493
494  t = inf_ptrace_target ();
495  t->to_fetch_registers = armnbsd_fetch_registers;
496  t->to_store_registers = armnbsd_store_registers;
497  add_target (t);
498
499  deprecated_add_core_fns (&arm_netbsd_core_fns);
500  deprecated_add_core_fns (&arm_netbsd_elfcore_fns);
501}
502