]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/ppcobsd-tdep.c
* ppcobsd-tdep.c: Fix typo in comment.
[thirdparty/binutils-gdb.git] / gdb / ppcobsd-tdep.c
1 /* Target-dependent code for OpenBSD/powerpc.
2
3 Copyright 2004, 2005 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #include "defs.h"
23 #include "arch-utils.h"
24 #include "osabi.h"
25 #include "regcache.h"
26 #include "regset.h"
27 #include "trad-frame.h"
28 #include "tramp-frame.h"
29
30 #include "gdb_assert.h"
31 #include "gdb_string.h"
32
33 #include "ppc-tdep.h"
34 #include "ppcobsd-tdep.h"
35 #include "solib-svr4.h"
36
37 /* Register offsets from <machine/reg.h>. */
38 struct ppc_reg_offsets ppcobsd_reg_offsets;
39 \f
40
41 /* Core file support. */
42
43 /* Supply register REGNUM in the general-purpose register set REGSET
44 from the buffer specified by GREGS and LEN to register cache
45 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
46
47 void
48 ppcobsd_supply_gregset (const struct regset *regset,
49 struct regcache *regcache, int regnum,
50 const void *gregs, size_t len)
51 {
52 /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
53 point registers. Traditionally, GDB's register set has still
54 listed the floating point registers for such machines, so this
55 code is harmless. However, the new E500 port actually omits the
56 floating point registers entirely from the register set --- they
57 don't even have register numbers assigned to them.
58
59 It's not clear to me how best to update this code, so this assert
60 will alert the first person to encounter the OpenBSD/E500
61 combination to the problem. */
62 gdb_assert (ppc_floating_point_unit_p (current_gdbarch));
63
64 ppc_supply_gregset (regset, regcache, regnum, gregs, len);
65 ppc_supply_fpregset (regset, regcache, regnum, gregs, len);
66 }
67
68 /* Collect register REGNUM in the general-purpose register set
69 REGSET. from register cache REGCACHE into the buffer specified by
70 GREGS and LEN. If REGNUM is -1, do this for all registers in
71 REGSET. */
72
73 void
74 ppcobsd_collect_gregset (const struct regset *regset,
75 const struct regcache *regcache, int regnum,
76 void *gregs, size_t len)
77 {
78 /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
79 point registers. Traditionally, GDB's register set has still
80 listed the floating point registers for such machines, so this
81 code is harmless. However, the new E500 port actually omits the
82 floating point registers entirely from the register set --- they
83 don't even have register numbers assigned to them.
84
85 It's not clear to me how best to update this code, so this assert
86 will alert the first person to encounter the OpenBSD/E500
87 combination to the problem. */
88 gdb_assert (ppc_floating_point_unit_p (current_gdbarch));
89
90 ppc_collect_gregset (regset, regcache, regnum, gregs, len);
91 ppc_collect_fpregset (regset, regcache, regnum, gregs, len);
92 }
93
94 /* OpenBSD/powerpc register set. */
95
96 struct regset ppcobsd_gregset =
97 {
98 &ppcobsd_reg_offsets,
99 ppcobsd_supply_gregset
100 };
101
102 /* Return the appropriate register set for the core section identified
103 by SECT_NAME and SECT_SIZE. */
104
105 static const struct regset *
106 ppcobsd_regset_from_core_section (struct gdbarch *gdbarch,
107 const char *sect_name, size_t sect_size)
108 {
109 if (strcmp (sect_name, ".reg") == 0 && sect_size >= 412)
110 return &ppcobsd_gregset;
111
112 return NULL;
113 }
114 \f
115
116 /* Signal trampolines. */
117
118 static void
119 ppcobsd_sigtramp_cache_init (const struct tramp_frame *self,
120 struct frame_info *next_frame,
121 struct trad_frame_cache *this_cache,
122 CORE_ADDR func)
123 {
124 struct gdbarch *gdbarch = get_frame_arch (next_frame);
125 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
126 CORE_ADDR addr, base;
127 int i;
128
129 base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
130 addr = base + 0x18 + 2 * tdep->wordsize;
131 for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize)
132 {
133 int regnum = i + tdep->ppc_gp0_regnum;
134 trad_frame_set_reg_addr (this_cache, regnum, addr);
135 }
136 trad_frame_set_reg_addr (this_cache, tdep->ppc_lr_regnum, addr);
137 addr += tdep->wordsize;
138 trad_frame_set_reg_addr (this_cache, tdep->ppc_cr_regnum, addr);
139 addr += tdep->wordsize;
140 trad_frame_set_reg_addr (this_cache, tdep->ppc_xer_regnum, addr);
141 addr += tdep->wordsize;
142 trad_frame_set_reg_addr (this_cache, tdep->ppc_ctr_regnum, addr);
143 addr += tdep->wordsize;
144 trad_frame_set_reg_addr (this_cache, PC_REGNUM, addr); /* SRR0? */
145 addr += tdep->wordsize;
146
147 /* Construct the frame ID using the function start. */
148 trad_frame_set_id (this_cache, frame_id_build (base, func));
149 }
150
151 static const struct tramp_frame ppcobsd_sigtramp =
152 {
153 SIGTRAMP_FRAME,
154 4,
155 {
156 { 0x3821fff0, -1 }, /* add r1,r1,-16 */
157 { 0x4e800021, -1 }, /* blrl */
158 { 0x38610018, -1 }, /* addi r3,r1,24 */
159 { 0x38000067, -1 }, /* li r0,103 */
160 { 0x44000002, -1 }, /* sc */
161 { 0x38000001, -1 }, /* li r0,1 */
162 { 0x44000002, -1 }, /* sc */
163 { TRAMP_SENTINEL_INSN, -1 }
164 },
165 ppcobsd_sigtramp_cache_init
166 };
167 \f
168
169 static void
170 ppcobsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
171 {
172 /* OpenBSD uses SVR4-style shared libraries. */
173 set_solib_svr4_fetch_link_map_offsets
174 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
175
176 set_gdbarch_regset_from_core_section
177 (gdbarch, ppcobsd_regset_from_core_section);
178
179 tramp_frame_prepend_unwinder (gdbarch, &ppcobsd_sigtramp);
180 }
181 \f
182
183 /* OpenBSD uses uses the traditional NetBSD core file format, even for
184 ports that use ELF. */
185 #define GDB_OSABI_NETBSD_CORE GDB_OSABI_OPENBSD_ELF
186
187 static enum gdb_osabi
188 ppcobsd_core_osabi_sniffer (bfd *abfd)
189 {
190 if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
191 return GDB_OSABI_NETBSD_CORE;
192
193 return GDB_OSABI_UNKNOWN;
194 }
195 \f
196
197 /* Provide a prototype to silence -Wmissing-prototypes. */
198 void _initialize_ppcobsd_tdep (void);
199
200 void
201 _initialize_ppcobsd_tdep (void)
202 {
203 /* BFD doesn't set a flavour for NetBSD style a.out core files. */
204 gdbarch_register_osabi_sniffer (bfd_arch_powerpc, bfd_target_unknown_flavour,
205 ppcobsd_core_osabi_sniffer);
206
207 gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_OPENBSD_ELF,
208 ppcobsd_init_abi);
209 gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_OPENBSD_ELF,
210 ppcobsd_init_abi);
211
212 /* Avoid initializing the register offsets again if they were
213 already initailized by ppcobsd-nat.c. */
214 if (ppcobsd_reg_offsets.pc_offset == 0)
215 {
216 /* General-purpose registers. */
217 ppcobsd_reg_offsets.r0_offset = 0;
218 ppcobsd_reg_offsets.pc_offset = 384;
219 ppcobsd_reg_offsets.ps_offset = 388;
220 ppcobsd_reg_offsets.cr_offset = 392;
221 ppcobsd_reg_offsets.lr_offset = 396;
222 ppcobsd_reg_offsets.ctr_offset = 400;
223 ppcobsd_reg_offsets.xer_offset = 404;
224 ppcobsd_reg_offsets.mq_offset = 408;
225
226 /* Floating-point registers. */
227 ppcobsd_reg_offsets.f0_offset = 128;
228 ppcobsd_reg_offsets.fpscr_offset = -1;
229
230 /* AltiVec registers. */
231 ppcobsd_reg_offsets.vr0_offset = 0;
232 ppcobsd_reg_offsets.vscr_offset = 512;
233 ppcobsd_reg_offsets.vrsave_offset = 520;
234 }
235 }