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