]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/ppcobsd-tdep.c
* mips32-dsp.s: Add some tests for shra_r.ph, shrav_r.ph, shra_r.w,
[thirdparty/binutils-gdb.git] / gdb / ppcobsd-tdep.c
CommitLineData
d195bc9f
MK
1/* Target-dependent code for OpenBSD/powerpc.
2
197e01b6 3 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
d195bc9f
MK
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
197e01b6
EZ
19 Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
d195bc9f
MK
21
22#include "defs.h"
23#include "arch-utils.h"
5a49dfd0 24#include "floatformat.h"
0dbe1904
MK
25#include "frame.h"
26#include "frame-unwind.h"
d195bc9f
MK
27#include "osabi.h"
28#include "regcache.h"
29#include "regset.h"
0dbe1904 30#include "symtab.h"
18b2ae85 31#include "trad-frame.h"
d195bc9f 32
18b2ae85 33#include "gdb_assert.h"
d195bc9f
MK
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>. */
41struct 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
50void
51ppcobsd_supply_gregset (const struct regset *regset,
52 struct regcache *regcache, int regnum,
53 const void *gregs, size_t len)
54{
383f0f5b
JB
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
d195bc9f
MK
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
76void
77ppcobsd_collect_gregset (const struct regset *regset,
78 const struct regcache *regcache, int regnum,
79 void *gregs, size_t len)
80{
383f0f5b
JB
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
d195bc9f
MK
93 ppc_collect_gregset (regset, regcache, regnum, gregs, len);
94 ppc_collect_fpregset (regset, regcache, regnum, gregs, len);
95}
96
5d6210f0 97/* OpenBSD/powerpc register set. */
d195bc9f
MK
98
99struct 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
108static const struct regset *
109ppcobsd_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
18b2ae85
MK
119/* Signal trampolines. */
120
0dbe1904
MK
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. */
133static const int ppcobsd_page_size = 4096;
134
135/* Offset for sigreturn(2). */
136static const int ppcobsd_sigreturn_offset[] = {
137 0x98, /* OpenBSD 3.8 */
138 0x0c, /* OpenBSD 3.2 */
139 -1
140};
141
142static int
143ppcobsd_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
179static struct trad_frame_cache *
180ppcobsd_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
18b2ae85
MK
181{
182 struct gdbarch *gdbarch = get_frame_arch (next_frame);
183 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
0dbe1904
MK
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;
18b2ae85
MK
188 int i;
189
0dbe1904
MK
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
18b2ae85 207 base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
0dbe1904 208 addr = base + sigcontext_offset + 2 * tdep->wordsize;
18b2ae85
MK
209 for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize)
210 {
211 int regnum = i + tdep->ppc_gp0_regnum;
0dbe1904 212 trad_frame_set_reg_addr (cache, regnum, addr);
18b2ae85 213 }
0dbe1904 214 trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, addr);
18b2ae85 215 addr += tdep->wordsize;
0dbe1904 216 trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, addr);
18b2ae85 217 addr += tdep->wordsize;
0dbe1904 218 trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, addr);
18b2ae85 219 addr += tdep->wordsize;
0dbe1904 220 trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, addr);
18b2ae85 221 addr += tdep->wordsize;
0dbe1904 222 trad_frame_set_reg_addr (cache, PC_REGNUM, addr); /* SRR0? */
18b2ae85
MK
223 addr += tdep->wordsize;
224
225 /* Construct the frame ID using the function start. */
0dbe1904
MK
226 trad_frame_set_id (cache, frame_id_build (base, func));
227
228 return cache;
18b2ae85
MK
229}
230
0dbe1904
MK
231static void
232ppcobsd_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
241static void
242ppcobsd_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)
18b2ae85 247{
0dbe1904
MK
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
255static const struct frame_unwind ppcobsd_sigtramp_frame_unwind = {
18b2ae85 256 SIGTRAMP_FRAME,
0dbe1904
MK
257 ppcobsd_sigtramp_frame_this_id,
258 ppcobsd_sigtramp_frame_prev_register
18b2ae85 259};
0dbe1904
MK
260
261static const struct frame_unwind *
262ppcobsd_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}
18b2ae85 269\f
5d6210f0 270
d195bc9f
MK
271static void
272ppcobsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
273{
5a49dfd0
MK
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
a86c5ab2
MK
278 /* OpenBSD currently uses a broken GCC. */
279 set_gdbarch_return_value (gdbarch, ppc_sysv_abi_broken_return_value);
280
d195bc9f 281 /* OpenBSD uses SVR4-style shared libraries. */
d195bc9f
MK
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);
18b2ae85 287
0dbe1904 288 frame_unwind_append_sniffer (gdbarch, ppcobsd_sigtramp_frame_sniffer);
d195bc9f
MK
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
296static enum gdb_osabi
297ppcobsd_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. */
307void _initialize_ppcobsd_tdep (void);
308
309void
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
5d6210f0
MK
316 gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_OPENBSD_ELF,
317 ppcobsd_init_abi);
d195bc9f
MK
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}