1 /* $MirOS: src/gnu/usr.bin/binutils/gdb/ppcobsd-tdep.c,v 1.3 2005/06/05 21:24:22 tg Exp $ */
2
3 /* Target-dependent code for OpenBSD/powerpc and MirOS BSD/powerpc.
4
5 Copyright 2004, 2005 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 #include "arch-utils.h"
26 #include "floatformat.h"
27 #include "osabi.h"
28 #include "regcache.h"
29 #include "regset.h"
30 #include "trad-frame.h"
31 #include "tramp-frame.h"
32
33 #include "gdb_assert.h"
34 #include "gdb_string.h"
35
36 #include "ppc-tdep.h"
37 #include "ppcobsd-tdep.h"
38 #include "solib-svr4.h"
39
40 /* Register offsets from <machine/reg.h>. */
41 struct ppc_reg_offsets ppcobsd_reg_offsets;
42
43
44 /* Core file support. */
45
46 /* Supply register REGNUM in the general-purpose register set REGSET
47 from the buffer specified by GREGS and LEN to register cache
48 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
49
50 void
ppcobsd_supply_gregset(const struct regset * regset,struct regcache * regcache,int regnum,const void * gregs,size_t len)51 ppcobsd_supply_gregset (const struct regset *regset,
52 struct regcache *regcache, int regnum,
53 const void *gregs, size_t len)
54 {
55 /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
56 point registers. Traditionally, GDB's register set has still
57 listed the floating point registers for such machines, so this
58 code is harmless. However, the new E500 port actually omits the
59 floating point registers entirely from the register set --- they
60 don't even have register numbers assigned to them.
61
62 It's not clear to me how best to update this code, so this assert
63 will alert the first person to encounter the OpenBSD/E500
64 combination to the problem. */
65 gdb_assert (ppc_floating_point_unit_p (current_gdbarch));
66
67 ppc_supply_gregset (regset, regcache, regnum, gregs, len);
68 ppc_supply_fpregset (regset, regcache, regnum, gregs, len);
69 }
70
71 /* Collect register REGNUM in the general-purpose register set
72 REGSET. from register cache REGCACHE into the buffer specified by
73 GREGS and LEN. If REGNUM is -1, do this for all registers in
74 REGSET. */
75
76 void
ppcobsd_collect_gregset(const struct regset * regset,const struct regcache * regcache,int regnum,void * gregs,size_t len)77 ppcobsd_collect_gregset (const struct regset *regset,
78 const struct regcache *regcache, int regnum,
79 void *gregs, size_t len)
80 {
81 /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
82 point registers. Traditionally, GDB's register set has still
83 listed the floating point registers for such machines, so this
84 code is harmless. However, the new E500 port actually omits the
85 floating point registers entirely from the register set --- they
86 don't even have register numbers assigned to them.
87
88 It's not clear to me how best to update this code, so this assert
89 will alert the first person to encounter the OpenBSD/E500
90 combination to the problem. */
91 gdb_assert (ppc_floating_point_unit_p (current_gdbarch));
92
93 ppc_collect_gregset (regset, regcache, regnum, gregs, len);
94 ppc_collect_fpregset (regset, regcache, regnum, gregs, len);
95 }
96
97 /* OpenBSD/powerpc register set. */
98
99 struct regset ppcobsd_gregset =
100 {
101 &ppcobsd_reg_offsets,
102 ppcobsd_supply_gregset
103 };
104
105 /* Return the appropriate register set for the core section identified
106 by SECT_NAME and SECT_SIZE. */
107
108 static const struct regset *
ppcobsd_regset_from_core_section(struct gdbarch * gdbarch,const char * sect_name,size_t sect_size)109 ppcobsd_regset_from_core_section (struct gdbarch *gdbarch,
110 const char *sect_name, size_t sect_size)
111 {
112 if (strcmp (sect_name, ".reg") == 0 && sect_size >= 412)
113 return &ppcobsd_gregset;
114
115 return NULL;
116 }
117
118
119 /* Signal trampolines. */
120
121 static void
ppcobsd_sigtramp_cache_init(const struct tramp_frame * self,struct frame_info * next_frame,struct trad_frame_cache * this_cache,CORE_ADDR func)122 ppcobsd_sigtramp_cache_init (const struct tramp_frame *self,
123 struct frame_info *next_frame,
124 struct trad_frame_cache *this_cache,
125 CORE_ADDR func)
126 {
127 struct gdbarch *gdbarch = get_frame_arch (next_frame);
128 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
129 CORE_ADDR addr, base;
130 int i;
131
132 base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
133 addr = base + 0x18 + 2 * tdep->wordsize;
134 for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize)
135 {
136 int regnum = i + tdep->ppc_gp0_regnum;
137 trad_frame_set_reg_addr (this_cache, regnum, addr);
138 }
139 trad_frame_set_reg_addr (this_cache, tdep->ppc_lr_regnum, addr);
140 addr += tdep->wordsize;
141 trad_frame_set_reg_addr (this_cache, tdep->ppc_cr_regnum, addr);
142 addr += tdep->wordsize;
143 trad_frame_set_reg_addr (this_cache, tdep->ppc_xer_regnum, addr);
144 addr += tdep->wordsize;
145 trad_frame_set_reg_addr (this_cache, tdep->ppc_ctr_regnum, addr);
146 addr += tdep->wordsize;
147 trad_frame_set_reg_addr (this_cache, PC_REGNUM, addr); /* SRR0? */
148 addr += tdep->wordsize;
149
150 /* Construct the frame ID using the function start. */
151 trad_frame_set_id (this_cache, frame_id_build (base, func));
152 }
153
154 static const struct tramp_frame ppcobsd_sigtramp =
155 {
156 SIGTRAMP_FRAME,
157 4,
158 {
159 { 0x3821fff0, -1 }, /* add r1,r1,-16 */
160 { 0x4e800021, -1 }, /* blrl */
161 { 0x38610018, -1 }, /* addi r3,r1,24 */
162 { 0x38000067, -1 }, /* li r0,103 */
163 { 0x44000002, -1 }, /* sc */
164 { 0x38000001, -1 }, /* li r0,1 */
165 { 0x44000002, -1 }, /* sc */
166 { TRAMP_SENTINEL_INSN, -1 }
167 },
168 ppcobsd_sigtramp_cache_init
169 };
170
171
172 static void
ppcobsd_init_abi(struct gdbarch_info info,struct gdbarch * gdbarch)173 ppcobsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
174 {
175 /* OpenBSD doesn't support the 128-bit `long double' from the psABI. */
176 set_gdbarch_long_double_bit (gdbarch, 64);
177 set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
178
179 /* OpenBSD currently uses a broken GCC. */
180 set_gdbarch_return_value (gdbarch, ppc_sysv_abi_broken_return_value);
181
182 /* OpenBSD uses SVR4-style shared libraries. */
183 set_solib_svr4_fetch_link_map_offsets
184 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
185
186 set_gdbarch_regset_from_core_section
187 (gdbarch, ppcobsd_regset_from_core_section);
188
189 tramp_frame_prepend_unwinder (gdbarch, &ppcobsd_sigtramp);
190 }
191
192
193 /* OpenBSD uses uses the traditional NetBSD core file format, even for
194 ports that use ELF. */
195 #define GDB_OSABI_NETBSD_CORE GDB_OSABI_OPENBSD_ELF
196
197 static enum gdb_osabi
ppcobsd_core_osabi_sniffer(bfd * abfd)198 ppcobsd_core_osabi_sniffer (bfd *abfd)
199 {
200 if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
201 return GDB_OSABI_NETBSD_CORE;
202
203 return GDB_OSABI_UNKNOWN;
204 }
205
206 /* Same for MirOS BSD. */
207 #define GDB_OSABI_MIRBSD_CORE GDB_OSABI_MIRBSD
208
209 static enum gdb_osabi
ppcmbsd_core_osabi_sniffer(bfd * abfd)210 ppcmbsd_core_osabi_sniffer (bfd *abfd)
211 {
212 if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
213 return GDB_OSABI_MIRBSD_CORE;
214
215 return GDB_OSABI_UNKNOWN;
216 }
217
218
219 /* Provide a prototype to silence -Wmissing-prototypes. */
220 void _initialize_ppcobsd_tdep (void);
221
222 void
_initialize_ppcobsd_tdep(void)223 _initialize_ppcobsd_tdep (void)
224 {
225 /* BFD doesn't set a flavour for NetBSD style a.out core files. */
226 gdbarch_register_osabi_sniffer (bfd_arch_powerpc, bfd_target_unknown_flavour,
227 ppcobsd_core_osabi_sniffer);
228
229 gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_OPENBSD_ELF,
230 ppcobsd_init_abi);
231 gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_OPENBSD_ELF,
232 ppcobsd_init_abi);
233
234 /* Avoid initializing the register offsets again if they were
235 already initailized by ppcobsd-nat.c. */
236 if (ppcobsd_reg_offsets.pc_offset == 0)
237 {
238 /* General-purpose registers. */
239 ppcobsd_reg_offsets.r0_offset = 0;
240 ppcobsd_reg_offsets.pc_offset = 384;
241 ppcobsd_reg_offsets.ps_offset = 388;
242 ppcobsd_reg_offsets.cr_offset = 392;
243 ppcobsd_reg_offsets.lr_offset = 396;
244 ppcobsd_reg_offsets.ctr_offset = 400;
245 ppcobsd_reg_offsets.xer_offset = 404;
246 ppcobsd_reg_offsets.mq_offset = 408;
247
248 /* Floating-point registers. */
249 ppcobsd_reg_offsets.f0_offset = 128;
250 ppcobsd_reg_offsets.fpscr_offset = -1;
251
252 /* AltiVec registers. */
253 ppcobsd_reg_offsets.vr0_offset = 0;
254 ppcobsd_reg_offsets.vscr_offset = 512;
255 ppcobsd_reg_offsets.vrsave_offset = 520;
256 }
257 }
258
259
260 /* MirOS BSD/powerpc is virtually identical to OpenBSD/powerpc. */
261
262 /* Provide a prototype to silence -Wmissing-prototypes. */
263 void _initialize_ppcmbsd_tdep (void);
264
265 void
_initialize_ppcmbsd_tdep(void)266 _initialize_ppcmbsd_tdep (void)
267 {
268 /* BFD doesn't set a flavour for NetBSD style a.out core files. */
269 gdbarch_register_osabi_sniffer (bfd_arch_powerpc, bfd_target_unknown_flavour,
270 ppcmbsd_core_osabi_sniffer);
271
272 gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_MIRBSD,
273 ppcobsd_init_abi);
274
275 /* Avoid initializing the register offsets again if they were
276 already initailized by ppcobsd-nat.c. */
277 if (ppcobsd_reg_offsets.pc_offset == 0)
278 {
279 /* General-purpose registers. */
280 ppcobsd_reg_offsets.r0_offset = 0;
281 ppcobsd_reg_offsets.pc_offset = 384;
282 ppcobsd_reg_offsets.ps_offset = 388;
283 ppcobsd_reg_offsets.cr_offset = 392;
284 ppcobsd_reg_offsets.lr_offset = 396;
285 ppcobsd_reg_offsets.ctr_offset = 400;
286 ppcobsd_reg_offsets.xer_offset = 404;
287 ppcobsd_reg_offsets.mq_offset = 408;
288
289 /* Floating-point registers. */
290 ppcobsd_reg_offsets.f0_offset = 128;
291 ppcobsd_reg_offsets.fpscr_offset = -1;
292
293 /* AltiVec registers. */
294 ppcobsd_reg_offsets.vr0_offset = 0;
295 ppcobsd_reg_offsets.vscr_offset = 512;
296 ppcobsd_reg_offsets.vrsave_offset = 520;
297 }
298 }
299