1162298Simp/* $FreeBSD$ */
2162298Simp
3162298Simp /* Native-dependent code for BSD Unix running on ARM's, for GDB.
4162298Simp   Copyright 1988, 1989, 1991, 1992, 1994, 1996, 1999, 2002
5162298Simp   Free Software Foundation, Inc.
6162298Simp
7162298Simp   This file is part of GDB.
8162298Simp
9162298Simp   This program is free software; you can redistribute it and/or modify
10162298Simp   it under the terms of the GNU General Public License as published by
11162298Simp   the Free Software Foundation; either version 2 of the License, or
12162298Simp   (at your option) any later version.
13162298Simp
14162298Simp   This program is distributed in the hope that it will be useful,
15162298Simp   but WITHOUT ANY WARRANTY; without even the implied warranty of
16162298Simp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17162298Simp   GNU General Public License for more details.
18162298Simp
19162298Simp   You should have received a copy of the GNU General Public License
20162298Simp   along with this program; if not, write to the Free Software
21162298Simp   Foundation, Inc., 59 Temple Place - Suite 330,
22162298Simp   Boston, MA 02111-1307, USA.  */
23162298Simp
24162298Simp#include "defs.h"
25162298Simp
26162298Simp#ifndef FETCH_INFERIOR_REGISTERS
27162298Simp#ifndef CROSS_DEBUGGER
28162298Simp#error Not FETCH_INFERIOR_REGISTERS
29162298Simp#endif
30162298Simp#endif /* !FETCH_INFERIOR_REGISTERS */
31162298Simp
32162298Simp#include "arm-tdep.h"
33162298Simp
34162298Simp#include <sys/types.h>
35225190Scognet#ifndef CROSS_DEBUGGER
36162298Simp#include <sys/ptrace.h>
37162298Simp#include <machine/reg.h>
38162298Simp#include <machine/frame.h>
39162298Simp#endif
40162298Simp#include "inferior.h"
41162298Simp#include "regcache.h"
42162298Simp#include "gdbcore.h"
43162298Simp
44162298Simpextern int arm_apcs_32;
45162298Simp
46162298Simp#ifdef CROSS_DEBUGGER
47162298Simpstruct reg {
48162298Simp	unsigned int r[13];
49162298Simp	unsigned int r_sp;
50162298Simp	unsigned int r_lr;
51162298Simp	unsigned int r_pc;
52162298Simp	unsigned int r_cpsr;
53162298Simp};
54162298Simp
55162298Simptypedef struct fp_extended_precision {
56162298Simp	u_int32_t fp_exponent;
57162298Simp	u_int32_t fp_mantissa_hi;
58162298Simp	u_int32_t fp_mantissa_lo;
59162298Simp} fp_extended_precision_t;
60162298Simp
61162298Simptypedef struct fp_extended_precision fp_reg_t;
62162298Simp
63162298Simpstruct fpreg {
64162298Simp	unsigned int fpr_fpsr;
65162298Simp	fp_reg_t fpr[8];
66162298Simp};
67162298Simp#endif
68162298Simp
69162298Simpvoid
70162298Simpsupply_gregset (struct reg *gregset)
71162298Simp{
72162298Simp  int regno;
73162298Simp  CORE_ADDR r_pc;
74162298Simp
75162298Simp  /* Integer registers.  */
76162298Simp  for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
77162298Simp    supply_register (regno, (char *) &gregset->r[regno]);
78162298Simp
79162298Simp  supply_register (ARM_SP_REGNUM, (char *) &gregset->r_sp);
80162298Simp  supply_register (ARM_LR_REGNUM, (char *) &gregset->r_lr);
81173705Scognet  supply_register (ARM_PC_REGNUM, (char *) &gregset->r_pc);
82162298Simp
83162298Simp  if (arm_apcs_32)
84162298Simp    supply_register (ARM_PS_REGNUM, (char *) &gregset->r_cpsr);
85162298Simp  else
86162298Simp    supply_register (ARM_PS_REGNUM, (char *) &gregset->r_pc);
87162298Simp}
88162298Simp
89173705Scognet/* Fill register REGNO (if it is a general-purpose register) in
90173705Scognet   *GREGSETPS with the value in GDB's register array.  If REGNO is -1,
91173705Scognet   do this for all registers.  */
92173705Scognet
93162298Simpvoid
94173705Scognetfill_gregset (struct reg *gregset, int regno)
95173705Scognet{
96173705Scognet  int i;
97173705Scognet
98173705Scognet  for (i = ARM_A1_REGNUM; i < ARM_SP_REGNUM; i++)
99173705Scognet    if ((regno == -1 || regno == i))
100173705Scognet      regcache_collect (i, &gregset->r[i]);
101173705Scognet  if (regno == -1 || regno == ARM_SP_REGNUM)
102173705Scognet      regcache_collect (ARM_SP_REGNUM, &gregset->r_sp);
103173705Scognet  if (regno == -1 || regno == ARM_LR_REGNUM)
104173705Scognet      regcache_collect (ARM_LR_REGNUM, &gregset->r_lr);
105173705Scognet  if (regno == -1 || regno == ARM_PC_REGNUM)
106173705Scognet      regcache_collect (ARM_PC_REGNUM, &gregset->r_pc);
107173705Scognet  if (regno == -1 || regno == ARM_PS_REGNUM)
108173705Scognet      regcache_collect (ARM_PS_REGNUM, &gregset->r_cpsr);
109173705Scognet}
110173705Scognet
111173705Scognetvoid
112162298Simpsupply_fpregset (struct fpreg *fparegset)
113162298Simp{
114162298Simp  int regno;
115162298Simp
116162298Simp  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
117162298Simp    supply_register
118162298Simp      (regno, (char *) &fparegset->fpr[regno - ARM_F0_REGNUM]);
119162298Simp
120162298Simp  supply_register (ARM_FPS_REGNUM, (char *) &fparegset->fpr_fpsr);
121162298Simp}
122162298Simp
123173705Scognetvoid
124173705Scognetfill_fpregset (struct fpreg *fparegset, int regno)
125173705Scognet{
126173705Scognet  int i;
127173705Scognet
128173705Scognet  for (i = ARM_F0_REGNUM; i <= ARM_F7_REGNUM; i++)
129173705Scognet    if (regno == -1 || regno == i)
130173705Scognet      regcache_raw_supply(current_regcache, i,
131173705Scognet	  &fparegset->fpr[i - ARM_F0_REGNUM]);
132173705Scognet  if (regno == -1 || regno == ARM_FPS_REGNUM)
133173705Scognet    regcache_raw_supply(current_regcache, ARM_FPS_REGNUM,
134173705Scognet	&fparegset->fpr_fpsr);
135173705Scognet}
136173705Scognet
137162298Simpstatic void
138162298Simpfetch_register (int regno)
139162298Simp{
140162298Simp  struct reg inferior_registers;
141162298Simp#ifndef CROSS_DEBUGGER
142162298Simp  int ret;
143162298Simp
144162298Simp  ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
145162298Simp		(PTRACE_ARG3_TYPE) &inferior_registers, 0);
146162298Simp
147162298Simp  if (ret < 0)
148162298Simp    {
149162298Simp      warning ("unable to fetch general register");
150162298Simp      return;
151162298Simp    }
152162298Simp#endif
153162298Simp
154162298Simp  switch (regno)
155162298Simp    {
156162298Simp    case ARM_SP_REGNUM:
157162298Simp      supply_register (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp);
158162298Simp      break;
159162298Simp
160162298Simp    case ARM_LR_REGNUM:
161162298Simp      supply_register (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr);
162162298Simp      break;
163162298Simp
164162298Simp    case ARM_PC_REGNUM:
165162298Simp      /* This is ok: we're running native... */
166162298Simp      inferior_registers.r_pc = ADDR_BITS_REMOVE (inferior_registers.r_pc);
167162298Simp      supply_register (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc);
168162298Simp      break;
169162298Simp
170162298Simp    case ARM_PS_REGNUM:
171162298Simp      if (arm_apcs_32)
172162298Simp	supply_register (ARM_PS_REGNUM, (char *) &inferior_registers.r_cpsr);
173162298Simp      else
174162298Simp	supply_register (ARM_PS_REGNUM, (char *) &inferior_registers.r_pc);
175162298Simp      break;
176162298Simp
177162298Simp    default:
178162298Simp      supply_register (regno, (char *) &inferior_registers.r[regno]);
179162298Simp      break;
180162298Simp    }
181162298Simp}
182162298Simp
183162298Simpstatic void
184162298Simpfetch_regs (void)
185162298Simp{
186162298Simp  struct reg inferior_registers;
187162298Simp#ifndef CROSS_DEBUGGER
188162298Simp  int ret;
189162298Simp#endif
190162298Simp  int regno;
191162298Simp
192162298Simp#ifndef CROSS_DEBUGGER
193162298Simp  ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
194162298Simp		(PTRACE_ARG3_TYPE) &inferior_registers, 0);
195162298Simp
196162298Simp  if (ret < 0)
197162298Simp    {
198162298Simp      warning ("unable to fetch general registers");
199162298Simp      return;
200162298Simp    }
201162298Simp#endif
202162298Simp
203162298Simp  supply_gregset (&inferior_registers);
204162298Simp}
205162298Simp
206162298Simpstatic void
207162298Simpfetch_fp_register (int regno)
208162298Simp{
209162298Simp  struct fpreg inferior_fp_registers;
210162298Simp#ifndef CROSS_DEBUGGER
211162298Simp  int ret;
212162298Simp
213162298Simp  ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
214162298Simp		(PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
215162298Simp
216162298Simp  if (ret < 0)
217162298Simp    {
218162298Simp      warning ("unable to fetch floating-point register");
219162298Simp      return;
220162298Simp    }
221162298Simp#endif
222162298Simp
223162298Simp  switch (regno)
224162298Simp    {
225162298Simp    case ARM_FPS_REGNUM:
226162298Simp      supply_register (ARM_FPS_REGNUM,
227162298Simp		       (char *) &inferior_fp_registers.fpr_fpsr);
228162298Simp      break;
229162298Simp
230162298Simp    default:
231162298Simp      supply_register
232162298Simp	(regno, (char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
233162298Simp      break;
234162298Simp    }
235162298Simp}
236162298Simp
237162298Simpstatic void
238162298Simpfetch_fp_regs (void)
239162298Simp{
240162298Simp  struct fpreg inferior_fp_registers;
241162298Simp#ifndef CROSS_DEBUGGER
242162298Simp  int ret;
243162298Simp#endif
244162298Simp  int regno;
245162298Simp
246162298Simp#ifndef CROSS_DEBUGGER
247162298Simp  ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
248162298Simp		(PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
249162298Simp
250162298Simp  if (ret < 0)
251162298Simp    {
252162298Simp      warning ("unable to fetch general registers");
253162298Simp      return;
254162298Simp    }
255162298Simp#endif
256162298Simp
257162298Simp  supply_fpregset (&inferior_fp_registers);
258162298Simp}
259162298Simp
260162298Simpvoid
261162298Simpfetch_inferior_registers (int regno)
262162298Simp{
263162298Simp  if (regno >= 0)
264162298Simp    {
265162298Simp      if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
266162298Simp	fetch_register (regno);
267162298Simp      else
268162298Simp	fetch_fp_register (regno);
269162298Simp    }
270162298Simp  else
271162298Simp    {
272162298Simp      fetch_regs ();
273162298Simp      fetch_fp_regs ();
274162298Simp    }
275162298Simp}
276162298Simp
277162298Simp
278162298Simpstatic void
279162298Simpstore_register (int regno)
280162298Simp{
281162298Simp  struct reg inferior_registers;
282162298Simp#ifndef CROSS_DEBUGGER
283162298Simp  int ret;
284162298Simp
285162298Simp  ret = ptrace (PT_GETREGS, PIDGET (inferior_ptid),
286162298Simp		(PTRACE_ARG3_TYPE) &inferior_registers, 0);
287162298Simp
288162298Simp  if (ret < 0)
289162298Simp    {
290162298Simp      warning ("unable to fetch general registers");
291162298Simp      return;
292162298Simp    }
293162298Simp#endif
294162298Simp
295162298Simp  switch (regno)
296162298Simp    {
297162298Simp    case ARM_SP_REGNUM:
298162298Simp      regcache_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp);
299162298Simp      break;
300162298Simp
301162298Simp    case ARM_LR_REGNUM:
302162298Simp      regcache_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr);
303162298Simp      break;
304162298Simp
305162298Simp    case ARM_PC_REGNUM:
306162298Simp      if (arm_apcs_32)
307162298Simp	regcache_collect (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc);
308162298Simp      else
309162298Simp	{
310162298Simp	  unsigned pc_val;
311162298Simp
312162298Simp	  regcache_collect (ARM_PC_REGNUM, (char *) &pc_val);
313162298Simp
314162298Simp	  pc_val = ADDR_BITS_REMOVE (pc_val);
315162298Simp	  inferior_registers.r_pc
316162298Simp	    ^= ADDR_BITS_REMOVE (inferior_registers.r_pc);
317162298Simp	  inferior_registers.r_pc |= pc_val;
318162298Simp	}
319162298Simp      break;
320162298Simp
321162298Simp    case ARM_PS_REGNUM:
322162298Simp      if (arm_apcs_32)
323162298Simp	regcache_collect (ARM_PS_REGNUM, (char *) &inferior_registers.r_cpsr);
324162298Simp      else
325162298Simp	{
326162298Simp	  unsigned psr_val;
327162298Simp
328162298Simp	  regcache_collect (ARM_PS_REGNUM, (char *) &psr_val);
329162298Simp
330162298Simp	  psr_val ^= ADDR_BITS_REMOVE (psr_val);
331162298Simp	  inferior_registers.r_pc = ADDR_BITS_REMOVE (inferior_registers.r_pc);
332162298Simp	  inferior_registers.r_pc |= psr_val;
333162298Simp	}
334162298Simp      break;
335162298Simp
336162298Simp    default:
337162298Simp      regcache_collect (regno, (char *) &inferior_registers.r[regno]);
338162298Simp      break;
339162298Simp    }
340162298Simp
341162298Simp#ifndef CROSS_DEBUGGER
342162298Simp  ret = ptrace (PT_SETREGS, PIDGET (inferior_ptid),
343162298Simp		(PTRACE_ARG3_TYPE) &inferior_registers, 0);
344162298Simp
345162298Simp  if (ret < 0)
346162298Simp    warning ("unable to write register %d to inferior", regno);
347162298Simp#endif
348162298Simp}
349162298Simp
350162298Simpstatic void
351162298Simpstore_regs (void)
352162298Simp{
353162298Simp  struct reg inferior_registers;
354162298Simp  int ret;
355162298Simp  int regno;
356162298Simp
357162298Simp
358162298Simp  for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
359162298Simp    regcache_collect (regno, (char *) &inferior_registers.r[regno]);
360162298Simp
361162298Simp  regcache_collect (ARM_SP_REGNUM, (char *) &inferior_registers.r_sp);
362162298Simp  regcache_collect (ARM_LR_REGNUM, (char *) &inferior_registers.r_lr);
363162298Simp
364162298Simp  if (arm_apcs_32)
365162298Simp    {
366162298Simp      regcache_collect (ARM_PC_REGNUM, (char *) &inferior_registers.r_pc);
367162298Simp      regcache_collect (ARM_PS_REGNUM, (char *) &inferior_registers.r_cpsr);
368162298Simp    }
369162298Simp  else
370162298Simp    {
371162298Simp      unsigned pc_val;
372162298Simp      unsigned psr_val;
373162298Simp
374162298Simp      regcache_collect (ARM_PC_REGNUM, (char *) &pc_val);
375162298Simp      regcache_collect (ARM_PS_REGNUM, (char *) &psr_val);
376162298Simp
377162298Simp      pc_val = ADDR_BITS_REMOVE (pc_val);
378162298Simp      psr_val ^= ADDR_BITS_REMOVE (psr_val);
379162298Simp
380162298Simp      inferior_registers.r_pc = pc_val | psr_val;
381162298Simp    }
382162298Simp
383162298Simp#ifndef CROSS_DEBUGGER
384162298Simp  ret = ptrace (PT_SETREGS, PIDGET (inferior_ptid),
385162298Simp		(PTRACE_ARG3_TYPE) &inferior_registers, 0);
386162298Simp
387162298Simp  if (ret < 0)
388162298Simp    warning ("unable to store general registers");
389162298Simp#endif
390162298Simp}
391162298Simp
392162298Simpstatic void
393162298Simpstore_fp_register (int regno)
394162298Simp{
395162298Simp  struct fpreg inferior_fp_registers;
396162298Simp#ifndef CROSS_DEBUGGER
397162298Simp  int ret;
398162298Simp
399162298Simp  ret = ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
400162298Simp		(PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
401162298Simp
402162298Simp  if (ret < 0)
403162298Simp    {
404162298Simp      warning ("unable to fetch floating-point registers");
405162298Simp      return;
406162298Simp    }
407162298Simp#endif
408162298Simp
409162298Simp  switch (regno)
410162298Simp    {
411162298Simp    case ARM_FPS_REGNUM:
412162298Simp      regcache_collect (ARM_FPS_REGNUM,
413162298Simp			(char *) &inferior_fp_registers.fpr_fpsr);
414162298Simp      break;
415162298Simp
416162298Simp    default:
417162298Simp      regcache_collect
418162298Simp	(regno, (char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
419162298Simp      break;
420162298Simp    }
421162298Simp
422162298Simp#ifndef CROSS_DEBUGGER
423162298Simp  ret = ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
424162298Simp		(PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
425162298Simp
426162298Simp  if (ret < 0)
427162298Simp    warning ("unable to write register %d to inferior", regno);
428162298Simp#endif
429162298Simp}
430162298Simp
431162298Simpstatic void
432162298Simpstore_fp_regs (void)
433162298Simp{
434162298Simp  struct fpreg inferior_fp_registers;
435162298Simp  int ret;
436162298Simp  int regno;
437162298Simp
438162298Simp
439162298Simp  for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++)
440162298Simp    regcache_collect
441162298Simp      (regno, (char *) &inferior_fp_registers.fpr[regno - ARM_F0_REGNUM]);
442162298Simp
443162298Simp  regcache_collect (ARM_FPS_REGNUM, (char *) &inferior_fp_registers.fpr_fpsr);
444162298Simp
445162298Simp#ifndef CROSS_DEBUGGER
446162298Simp  ret = ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
447162298Simp		(PTRACE_ARG3_TYPE) &inferior_fp_registers, 0);
448162298Simp
449162298Simp  if (ret < 0)
450162298Simp    warning ("unable to store floating-point registers");
451162298Simp#endif
452162298Simp}
453162298Simp
454162298Simpvoid
455162298Simpstore_inferior_registers (int regno)
456162298Simp{
457162298Simp  if (regno >= 0)
458162298Simp    {
459162298Simp      if (regno < ARM_F0_REGNUM || regno > ARM_FPS_REGNUM)
460162298Simp	store_register (regno);
461162298Simp      else
462162298Simp	store_fp_register (regno);
463162298Simp    }
464162298Simp  else
465162298Simp    {
466162298Simp      store_regs ();
467162298Simp      store_fp_regs ();
468162298Simp    }
469162298Simp}
470162298Simp
471162298Simp
472162298Simpstruct md_core
473162298Simp{
474162298Simp  struct reg intreg;
475162298Simp  struct fpreg freg;
476162298Simp};
477162298Simp
478162298Simpstatic void
479162298Simpfetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
480162298Simp		      int which, CORE_ADDR ignore)
481162298Simp{
482162298Simp  struct md_core *core_reg = (struct md_core *) core_reg_sect;
483162298Simp  int regno;
484162298Simp  CORE_ADDR r_pc;
485162298Simp
486162298Simp  supply_gregset (&core_reg->intreg);
487162298Simp  supply_fpregset (&core_reg->freg);
488162298Simp}
489162298Simp
490162298Simpstatic void
491162298Simpfetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size,
492162298Simp			 int which, CORE_ADDR ignore)
493162298Simp{
494162298Simp  struct reg gregset;
495162298Simp  struct fpreg fparegset;
496162298Simp
497162298Simp  switch (which)
498162298Simp    {
499162298Simp    case 0:	/* Integer registers.  */
500162298Simp      if (core_reg_size != sizeof (struct reg))
501162298Simp	warning ("wrong size of register set in core file");
502162298Simp      else
503162298Simp	{
504162298Simp	  /* The memcpy may be unnecessary, but we can't really be sure
505162298Simp	     of the alignment of the data in the core file.  */
506162298Simp	  memcpy (&gregset, core_reg_sect, sizeof (gregset));
507162298Simp	  supply_gregset (&gregset);
508162298Simp	}
509162298Simp      break;
510162298Simp
511162298Simp    case 2:
512162298Simp      if (core_reg_size != sizeof (struct fpreg))
513162298Simp	warning ("wrong size of FPA register set in core file");
514162298Simp      else
515162298Simp	{
516162298Simp	  /* The memcpy may be unnecessary, but we can't really be sure
517162298Simp	     of the alignment of the data in the core file.  */
518162298Simp	  memcpy (&fparegset, core_reg_sect, sizeof (fparegset));
519162298Simp	  supply_fpregset (&fparegset);
520162298Simp	}
521162298Simp      break;
522162298Simp
523162298Simp    default:
524162298Simp      /* Don't know what kind of register request this is; just ignore it.  */
525162298Simp      break;
526162298Simp    }
527162298Simp}
528162298Simp
529162298Simpstatic struct core_fns arm_freebsd_core_fns =
530162298Simp{
531162298Simp  bfd_target_unknown_flavour,		/* core_flovour.  */
532162298Simp  default_check_format,			/* check_format.  */
533162298Simp  default_core_sniffer,			/* core_sniffer.  */
534162298Simp  fetch_core_registers,			/* core_read_registers.  */
535162298Simp  NULL
536162298Simp};
537162298Simp
538162298Simpstatic struct core_fns arm_freebsd_elfcore_fns =
539162298Simp{
540162298Simp  bfd_target_elf_flavour,		/* core_flovour.  */
541162298Simp  default_check_format,			/* check_format.  */
542162298Simp  default_core_sniffer,			/* core_sniffer.  */
543162298Simp  fetch_elfcore_registers,		/* core_read_registers.  */
544162298Simp  NULL
545162298Simp};
546162298Simp
547162298Simpvoid
548162298Simp_initialize_arm_fbsdnat (void)
549162298Simp{
550162298Simp  add_core_fns (&arm_freebsd_core_fns);
551162298Simp  add_core_fns (&arm_freebsd_elfcore_fns);
552162298Simp}
553