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