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