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