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