1/* Target-dependent code for PowerPC systems running NetBSD.
2
3   Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
4
5   Contributed by Wasabi Systems, 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#include "gdbcore.h"
26#include "regcache.h"
27#include "target.h"
28#include "breakpoint.h"
29#include "value.h"
30#include "osabi.h"
31
32#include "ppc-tdep.h"
33#include "ppcnbsd-tdep.h"
34#include "nbsd-tdep.h"
35#include "tramp-frame.h"
36#include "trad-frame.h"
37#include "gdb_assert.h"
38#include "solib-svr4.h"
39
40#define REG_FIXREG_OFFSET(x)	((x) * 4)
41#define REG_LR_OFFSET		(32 * 4)
42#define REG_CR_OFFSET		(33 * 4)
43#define REG_XER_OFFSET		(34 * 4)
44#define REG_CTR_OFFSET		(35 * 4)
45#define REG_PC_OFFSET		(36 * 4)
46#define SIZEOF_STRUCT_REG	(37 * 4)
47
48#define FPREG_FPR_OFFSET(x)	((x) * 8)
49#define FPREG_FPSCR_OFFSET	(32 * 8)
50#define SIZEOF_STRUCT_FPREG	(33 * 8)
51
52void
53ppcnbsd_supply_reg (char *regs, int regno)
54{
55  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
56  int i;
57
58  for (i = 0; i < ppc_num_gprs; i++)
59    {
60      if (regno == tdep->ppc_gp0_regnum + i || regno == -1)
61	regcache_raw_supply (current_regcache, tdep->ppc_gp0_regnum + i,
62			     regs + REG_FIXREG_OFFSET (i));
63    }
64
65  if (regno == tdep->ppc_lr_regnum || regno == -1)
66    regcache_raw_supply (current_regcache, tdep->ppc_lr_regnum,
67			 regs + REG_LR_OFFSET);
68
69  if (regno == tdep->ppc_cr_regnum || regno == -1)
70    regcache_raw_supply (current_regcache, tdep->ppc_cr_regnum,
71			 regs + REG_CR_OFFSET);
72
73  if (regno == tdep->ppc_xer_regnum || regno == -1)
74    regcache_raw_supply (current_regcache, tdep->ppc_xer_regnum,
75			 regs + REG_XER_OFFSET);
76
77  if (regno == tdep->ppc_ctr_regnum || regno == -1)
78    regcache_raw_supply (current_regcache, tdep->ppc_ctr_regnum,
79			 regs + REG_CTR_OFFSET);
80
81  if (regno == PC_REGNUM || regno == -1)
82    regcache_raw_supply (current_regcache, PC_REGNUM,
83			 regs + REG_PC_OFFSET);
84}
85
86void
87ppcnbsd_fill_reg (char *regs, int regno)
88{
89  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
90  int i;
91
92  for (i = 0; i < ppc_num_gprs; i++)
93    {
94      if (regno == tdep->ppc_gp0_regnum + i || regno == -1)
95	regcache_raw_collect (current_regcache, tdep->ppc_gp0_regnum + i,
96			      regs + REG_FIXREG_OFFSET (i));
97    }
98
99  if (regno == tdep->ppc_lr_regnum || regno == -1)
100    regcache_raw_collect (current_regcache, tdep->ppc_lr_regnum,
101			  regs + REG_LR_OFFSET);
102
103  if (regno == tdep->ppc_cr_regnum || regno == -1)
104    regcache_raw_collect (current_regcache, tdep->ppc_cr_regnum,
105			  regs + REG_CR_OFFSET);
106
107  if (regno == tdep->ppc_xer_regnum || regno == -1)
108    regcache_raw_collect (current_regcache, tdep->ppc_xer_regnum,
109			  regs + REG_XER_OFFSET);
110
111  if (regno == tdep->ppc_ctr_regnum || regno == -1)
112    regcache_raw_collect (current_regcache, tdep->ppc_ctr_regnum,
113			  regs + REG_CTR_OFFSET);
114
115  if (regno == PC_REGNUM || regno == -1)
116    regcache_raw_collect (current_regcache, PC_REGNUM, regs + REG_PC_OFFSET);
117}
118
119void
120ppcnbsd_supply_fpreg (char *fpregs, int regno)
121{
122  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
123  int i;
124
125  /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
126     point registers.  Traditionally, GDB's register set has still
127     listed the floating point registers for such machines, so this
128     code is harmless.  However, the new E500 port actually omits the
129     floating point registers entirely from the register set --- they
130     don't even have register numbers assigned to them.
131
132     It's not clear to me how best to update this code, so this assert
133     will alert the first person to encounter the NetBSD/E500
134     combination to the problem.  */
135  gdb_assert (ppc_floating_point_unit_p (current_gdbarch));
136
137  for (i = 0; i < ppc_num_fprs; i++)
138    {
139      if (regno == tdep->ppc_fp0_regnum + i || regno == -1)
140	regcache_raw_supply (current_regcache, tdep->ppc_fp0_regnum + i,
141			     fpregs + FPREG_FPR_OFFSET (i));
142    }
143
144  if (regno == tdep->ppc_fpscr_regnum || regno == -1)
145    regcache_raw_supply (current_regcache, tdep->ppc_fpscr_regnum,
146			 fpregs + FPREG_FPSCR_OFFSET);
147}
148
149void
150ppcnbsd_fill_fpreg (char *fpregs, int regno)
151{
152  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
153  int i;
154
155  /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
156     point registers.  Traditionally, GDB's register set has still
157     listed the floating point registers for such machines, so this
158     code is harmless.  However, the new E500 port actually omits the
159     floating point registers entirely from the register set --- they
160     don't even have register numbers assigned to them.
161
162     It's not clear to me how best to update this code, so this assert
163     will alert the first person to encounter the NetBSD/E500
164     combination to the problem.  */
165  gdb_assert (ppc_floating_point_unit_p (current_gdbarch));
166
167  for (i = 0; i < ppc_num_fprs; i++)
168    {
169      if (regno == tdep->ppc_fp0_regnum + i || regno == -1)
170	regcache_raw_collect (current_regcache, tdep->ppc_fp0_regnum + i,
171			      fpregs + FPREG_FPR_OFFSET (i));
172    }
173
174  if (regno == tdep->ppc_fpscr_regnum || regno == -1)
175    regcache_raw_collect (current_regcache, tdep->ppc_fpscr_regnum,
176			  fpregs + FPREG_FPSCR_OFFSET);
177}
178
179static void
180fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
181                      CORE_ADDR ignore)
182{
183  char *regs, *fpregs;
184
185  /* We get everything from one section.  */
186  if (which != 0)
187    return;
188
189  regs = core_reg_sect;
190  fpregs = core_reg_sect + SIZEOF_STRUCT_REG;
191
192  /* Integer registers.  */
193  ppcnbsd_supply_reg (regs, -1);
194
195  /* Floating point registers.  */
196  ppcnbsd_supply_fpreg (fpregs, -1);
197}
198
199static void
200fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
201                         CORE_ADDR ignore)
202{
203  switch (which)
204    {
205    case 0:  /* Integer registers.  */
206      if (core_reg_size != SIZEOF_STRUCT_REG)
207	warning ("Wrong size register set in core file.");
208      else
209	ppcnbsd_supply_reg (core_reg_sect, -1);
210      break;
211
212    case 2:  /* Floating point registers.  */
213      if (core_reg_size != SIZEOF_STRUCT_FPREG)
214	warning ("Wrong size FP register set in core file.");
215      else
216	ppcnbsd_supply_fpreg (core_reg_sect, -1);
217      break;
218
219    default:
220      /* Don't know what kind of register request this is; just ignore it.  */
221      break;
222    }
223}
224
225static struct core_fns ppcnbsd_core_fns =
226{
227  bfd_target_unknown_flavour,		/* core_flavour */
228  default_check_format,			/* check_format */
229  default_core_sniffer,			/* core_sniffer */
230  fetch_core_registers,			/* core_read_registers */
231  NULL					/* next */
232};
233
234static struct core_fns ppcnbsd_elfcore_fns =
235{
236  bfd_target_elf_flavour,		/* core_flavour */
237  default_check_format,			/* check_format */
238  default_core_sniffer,			/* core_sniffer */
239  fetch_elfcore_registers,		/* core_read_registers */
240  NULL					/* next */
241};
242
243/* NetBSD is confused.  It appears that 1.5 was using the correct SVr4
244   convention but, 1.6 switched to the below broken convention.  For
245   the moment use the broken convention.  Ulgh!.  */
246
247static enum return_value_convention
248ppcnbsd_return_value (struct gdbarch *gdbarch, struct type *valtype,
249		      struct regcache *regcache, void *readbuf,
250		      const void *writebuf)
251{
252  if ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
253       || TYPE_CODE (valtype) == TYPE_CODE_UNION)
254      && !((TYPE_LENGTH (valtype) == 16 || TYPE_LENGTH (valtype) == 8)
255	    && TYPE_VECTOR (valtype))
256      && !(TYPE_LENGTH (valtype) == 1
257	   || TYPE_LENGTH (valtype) == 2
258	   || TYPE_LENGTH (valtype) == 4
259	   || TYPE_LENGTH (valtype) == 8))
260    return RETURN_VALUE_STRUCT_CONVENTION;
261  else
262    return ppc_sysv_abi_broken_return_value (gdbarch, valtype, regcache,
263					     readbuf, writebuf);
264}
265
266static void
267ppcnbsd_sigtramp_cache_init (const struct tramp_frame *self,
268			     struct frame_info *next_frame,
269			     struct trad_frame_cache *this_cache,
270			     CORE_ADDR func)
271{
272  CORE_ADDR base;
273  CORE_ADDR offset;
274  int i;
275  struct gdbarch *gdbarch = get_frame_arch (next_frame);
276  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
277
278  base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
279  offset = base + 0x18 + 2 * tdep->wordsize;
280  for (i = 0; i < ppc_num_gprs; i++)
281    {
282      int regnum = i + tdep->ppc_gp0_regnum;
283      trad_frame_set_reg_addr (this_cache, regnum, offset);
284      offset += tdep->wordsize;
285    }
286  trad_frame_set_reg_addr (this_cache, tdep->ppc_lr_regnum, offset);
287  offset += tdep->wordsize;
288  trad_frame_set_reg_addr (this_cache, tdep->ppc_cr_regnum, offset);
289  offset += tdep->wordsize;
290  trad_frame_set_reg_addr (this_cache, tdep->ppc_xer_regnum, offset);
291  offset += tdep->wordsize;
292  trad_frame_set_reg_addr (this_cache, tdep->ppc_ctr_regnum, offset);
293  offset += tdep->wordsize;
294  trad_frame_set_reg_addr (this_cache, PC_REGNUM, offset); /* SRR0? */
295  offset += tdep->wordsize;
296
297  /* Construct the frame ID using the function start.  */
298  trad_frame_set_id (this_cache, frame_id_build (base, func));
299}
300
301/* Given the NEXT frame, examine the instructions at and around this
302   frame's resume address (aka PC) to see of they look like a signal
303   trampoline.  Return the address of the trampolines first
304   instruction, or zero if it isn't a signal trampoline.  */
305
306static const struct tramp_frame ppcnbsd_sigtramp = {
307  SIGTRAMP_FRAME,
308  4, /* insn size */
309  { /* insn */
310    { 0x38610018, -1 }, /* addi r3,r1,24 */
311    { 0x38000127, -1 }, /* li r0,295 */
312    { 0x44000002, -1 }, /* sc */
313    { 0x38000001, -1 }, /* li r0,1 */
314    { 0x44000002, -1 }, /* sc */
315    { TRAMP_SENTINEL_INSN, -1 }
316  },
317  ppcnbsd_sigtramp_cache_init
318};
319
320static void
321ppcnbsd_init_abi (struct gdbarch_info info,
322                  struct gdbarch *gdbarch)
323{
324  /* For NetBSD, this is an on again, off again thing.  Some systems
325     do use the broken struct convention, and some don't.  */
326  set_gdbarch_return_value (gdbarch, ppcnbsd_return_value);
327  set_solib_svr4_fetch_link_map_offsets (gdbarch,
328                                nbsd_ilp32_solib_svr4_fetch_link_map_offsets);
329  tramp_frame_prepend_unwinder (gdbarch, &ppcnbsd_sigtramp);
330}
331
332void
333_initialize_ppcnbsd_tdep (void)
334{
335  gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_NETBSD_ELF,
336			  ppcnbsd_init_abi);
337
338  deprecated_add_core_fns (&ppcnbsd_core_fns);
339  deprecated_add_core_fns (&ppcnbsd_elfcore_fns);
340}
341