]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/ppcobsd-tdep.c
* breakpoint.c:
[thirdparty/binutils-gdb.git] / gdb / ppcobsd-tdep.c
1 /* Target-dependent code for OpenBSD/powerpc.
2
3 Copyright (C) 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., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
21
22 #include "defs.h"
23 #include "arch-utils.h"
24 #include "floatformat.h"
25 #include "frame.h"
26 #include "frame-unwind.h"
27 #include "osabi.h"
28 #include "regcache.h"
29 #include "regset.h"
30 #include "symtab.h"
31 #include "trad-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 \f
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
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
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 *
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 \f
118
119 /* Signal trampolines. */
120
121 /* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
122 in virtual memory. The randomness makes it somewhat tricky to
123 detect it, but fortunately we can rely on the fact that the start
124 of the sigtramp routine is page-aligned. We recognize the
125 trampoline by looking for the code that invokes the sigreturn
126 system call. The offset where we can find that code varies from
127 release to release.
128
129 By the way, the mapping mentioned above is read-only, so you cannot
130 place a breakpoint in the signal trampoline. */
131
132 /* Default page size. */
133 static const int ppcobsd_page_size = 4096;
134
135 /* Offset for sigreturn(2). */
136 static const int ppcobsd_sigreturn_offset[] = {
137 0x98, /* OpenBSD 3.8 */
138 0x0c, /* OpenBSD 3.2 */
139 -1
140 };
141
142 static int
143 ppcobsd_sigtramp_p (struct frame_info *next_frame)
144 {
145 CORE_ADDR pc = frame_pc_unwind (next_frame);
146 CORE_ADDR start_pc = (pc & ~(ppcobsd_page_size - 1));
147 const int *offset;
148 char *name;
149
150 find_pc_partial_function (pc, &name, NULL, NULL);
151 if (name)
152 return 0;
153
154 for (offset = ppcobsd_sigreturn_offset; *offset != -1; offset++)
155 {
156 gdb_byte buf[2 * PPC_INSN_SIZE];
157 unsigned long insn;
158
159 if (!safe_frame_unwind_memory (next_frame, start_pc + *offset,
160 buf, sizeof buf))
161 continue;
162
163 /* Check for "li r0,SYS_sigreturn". */
164 insn = extract_unsigned_integer (buf, PPC_INSN_SIZE);
165 if (insn != 0x38000067)
166 continue;
167
168 /* Check for "sc". */
169 insn = extract_unsigned_integer (buf + PPC_INSN_SIZE, PPC_INSN_SIZE);
170 if (insn != 0x44000002)
171 continue;
172
173 return 1;
174 }
175
176 return 0;
177 }
178
179 static struct trad_frame_cache *
180 ppcobsd_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
181 {
182 struct gdbarch *gdbarch = get_frame_arch (next_frame);
183 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
184 struct trad_frame_cache *cache;
185 CORE_ADDR addr, base, func;
186 gdb_byte buf[PPC_INSN_SIZE];
187 unsigned long insn, sigcontext_offset;
188 int i;
189
190 if (*this_cache)
191 return *this_cache;
192
193 cache = trad_frame_cache_zalloc (next_frame);
194 *this_cache = cache;
195
196 func = frame_pc_unwind (next_frame);
197 func &= ~(ppcobsd_page_size - 1);
198 if (!safe_frame_unwind_memory (next_frame, func, buf, sizeof buf))
199 return cache;
200
201 /* Calculate the offset where we can find `struct sigcontext'. We
202 base our calculation on the amount of stack space reserved by the
203 first instruction of the signal trampoline. */
204 insn = extract_unsigned_integer (buf, PPC_INSN_SIZE);
205 sigcontext_offset = (0x10000 - (insn & 0x0000ffff)) + 8;
206
207 base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
208 addr = base + sigcontext_offset + 2 * tdep->wordsize;
209 for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize)
210 {
211 int regnum = i + tdep->ppc_gp0_regnum;
212 trad_frame_set_reg_addr (cache, regnum, addr);
213 }
214 trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, addr);
215 addr += tdep->wordsize;
216 trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, addr);
217 addr += tdep->wordsize;
218 trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, addr);
219 addr += tdep->wordsize;
220 trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, addr);
221 addr += tdep->wordsize;
222 trad_frame_set_reg_addr (cache, PC_REGNUM, addr); /* SRR0? */
223 addr += tdep->wordsize;
224
225 /* Construct the frame ID using the function start. */
226 trad_frame_set_id (cache, frame_id_build (base, func));
227
228 return cache;
229 }
230
231 static void
232 ppcobsd_sigtramp_frame_this_id (struct frame_info *next_frame,
233 void **this_cache, struct frame_id *this_id)
234 {
235 struct trad_frame_cache *cache =
236 ppcobsd_sigtramp_frame_cache (next_frame, this_cache);
237
238 trad_frame_get_id (cache, this_id);
239 }
240
241 static void
242 ppcobsd_sigtramp_frame_prev_register (struct frame_info *next_frame,
243 void **this_cache, int regnum,
244 int *optimizedp, enum lval_type *lvalp,
245 CORE_ADDR *addrp, int *realnump,
246 gdb_byte *valuep)
247 {
248 struct trad_frame_cache *cache =
249 ppcobsd_sigtramp_frame_cache (next_frame, this_cache);
250
251 trad_frame_get_register (cache, next_frame, regnum,
252 optimizedp, lvalp, addrp, realnump, valuep);
253 }
254
255 static const struct frame_unwind ppcobsd_sigtramp_frame_unwind = {
256 SIGTRAMP_FRAME,
257 ppcobsd_sigtramp_frame_this_id,
258 ppcobsd_sigtramp_frame_prev_register
259 };
260
261 static const struct frame_unwind *
262 ppcobsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
263 {
264 if (ppcobsd_sigtramp_p (next_frame))
265 return &ppcobsd_sigtramp_frame_unwind;
266
267 return NULL;
268 }
269 \f
270
271 static void
272 ppcobsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
273 {
274 /* OpenBSD doesn't support the 128-bit `long double' from the psABI. */
275 set_gdbarch_long_double_bit (gdbarch, 64);
276 set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
277
278 /* OpenBSD currently uses a broken GCC. */
279 set_gdbarch_return_value (gdbarch, ppc_sysv_abi_broken_return_value);
280
281 /* OpenBSD uses SVR4-style shared libraries. */
282 set_solib_svr4_fetch_link_map_offsets
283 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
284
285 set_gdbarch_regset_from_core_section
286 (gdbarch, ppcobsd_regset_from_core_section);
287
288 frame_unwind_append_sniffer (gdbarch, ppcobsd_sigtramp_frame_sniffer);
289 }
290 \f
291
292 /* OpenBSD uses uses the traditional NetBSD core file format, even for
293 ports that use ELF. */
294 #define GDB_OSABI_NETBSD_CORE GDB_OSABI_OPENBSD_ELF
295
296 static enum gdb_osabi
297 ppcobsd_core_osabi_sniffer (bfd *abfd)
298 {
299 if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
300 return GDB_OSABI_NETBSD_CORE;
301
302 return GDB_OSABI_UNKNOWN;
303 }
304 \f
305
306 /* Provide a prototype to silence -Wmissing-prototypes. */
307 void _initialize_ppcobsd_tdep (void);
308
309 void
310 _initialize_ppcobsd_tdep (void)
311 {
312 /* BFD doesn't set a flavour for NetBSD style a.out core files. */
313 gdbarch_register_osabi_sniffer (bfd_arch_powerpc, bfd_target_unknown_flavour,
314 ppcobsd_core_osabi_sniffer);
315
316 gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_OPENBSD_ELF,
317 ppcobsd_init_abi);
318 gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_OPENBSD_ELF,
319 ppcobsd_init_abi);
320
321 /* Avoid initializing the register offsets again if they were
322 already initailized by ppcobsd-nat.c. */
323 if (ppcobsd_reg_offsets.pc_offset == 0)
324 {
325 /* General-purpose registers. */
326 ppcobsd_reg_offsets.r0_offset = 0;
327 ppcobsd_reg_offsets.pc_offset = 384;
328 ppcobsd_reg_offsets.ps_offset = 388;
329 ppcobsd_reg_offsets.cr_offset = 392;
330 ppcobsd_reg_offsets.lr_offset = 396;
331 ppcobsd_reg_offsets.ctr_offset = 400;
332 ppcobsd_reg_offsets.xer_offset = 404;
333 ppcobsd_reg_offsets.mq_offset = 408;
334
335 /* Floating-point registers. */
336 ppcobsd_reg_offsets.f0_offset = 128;
337 ppcobsd_reg_offsets.fpscr_offset = -1;
338
339 /* AltiVec registers. */
340 ppcobsd_reg_offsets.vr0_offset = 0;
341 ppcobsd_reg_offsets.vscr_offset = 512;
342 ppcobsd_reg_offsets.vrsave_offset = 520;
343 }
344 }