1 /* Target-dependent code for OpenBSD/powerpc64.
2
3 Copyright (C) 2004, 2005, 2006 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 "ppc64obsd-tdep.h"
38 #include "solib-svr4.h"
39
40 /* Register offsets from <machine/reg.h>. */
41 struct ppc_reg_offsets ppc64obsd_reg_offsets;
42 struct ppc_reg_offsets ppc64obsd_fpreg_offsets;
43
44
45 /* Register set support functions. */
46
47 static void
ppc64_supply_reg(struct regcache * regcache,int regnum,const char * regs,size_t offset)48 ppc64_supply_reg (struct regcache *regcache, int regnum,
49 const char *regs, size_t offset)
50 {
51 if (regnum != -1 && offset != -1)
52 regcache_raw_supply (regcache, regnum, regs + offset);
53 }
54
55 static void
ppc64_collect_reg(const struct regcache * regcache,int regnum,char * regs,size_t offset)56 ppc64_collect_reg (const struct regcache *regcache, int regnum,
57 char *regs, size_t offset)
58 {
59 if (regnum != -1 && offset != -1)
60 regcache_raw_collect (regcache, regnum, regs + offset);
61 }
62
63 /* Supply register REGNUM in the general-purpose register set REGSET
64 from the buffer specified by GREGS and LEN to register cache
65 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
66
67 void
ppc64_supply_gregset(const struct regset * regset,struct regcache * regcache,int regnum,const void * gregs,size_t len)68 ppc64_supply_gregset (const struct regset *regset, struct regcache *regcache,
69 int regnum, const void *gregs, size_t len)
70 {
71 struct gdbarch *gdbarch = get_regcache_arch (regcache);
72 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
73 const struct ppc_reg_offsets *offsets = regset->descr;
74 size_t offset;
75 int i;
76
77 for (i = tdep->ppc_gp0_regnum, offset = offsets->r0_offset;
78 i < tdep->ppc_gp0_regnum + ppc_num_gprs;
79 i++, offset += 8)
80 {
81 if (regnum == -1 || regnum == i)
82 ppc64_supply_reg (regcache, i, gregs, offset);
83 }
84
85 if (regnum == -1 || regnum == PC_REGNUM)
86 ppc64_supply_reg (regcache, PC_REGNUM, gregs, offsets->pc_offset);
87 if (regnum == -1 || regnum == tdep->ppc_ps_regnum)
88 ppc64_supply_reg (regcache, tdep->ppc_ps_regnum,
89 gregs, offsets->ps_offset);
90 if (regnum == -1 || regnum == tdep->ppc_cr_regnum)
91 ppc64_supply_reg (regcache, tdep->ppc_cr_regnum,
92 gregs, offsets->cr_offset);
93 if (regnum == -1 || regnum == tdep->ppc_lr_regnum)
94 ppc64_supply_reg (regcache, tdep->ppc_lr_regnum,
95 gregs, offsets->lr_offset);
96 if (regnum == -1 || regnum == tdep->ppc_ctr_regnum)
97 ppc64_supply_reg (regcache, tdep->ppc_ctr_regnum,
98 gregs, offsets->ctr_offset);
99 if (regnum == -1 || regnum == tdep->ppc_xer_regnum)
100 ppc64_supply_reg (regcache, tdep->ppc_xer_regnum,
101 gregs, offsets->cr_offset);
102 }
103
104 /* Collect register REGNUM in the general-purpose register set
105 REGSET. from register cache REGCACHE into the buffer specified by
106 GREGS and LEN. If REGNUM is -1, do this for all registers in
107 REGSET. */
108
109 void
ppc64_collect_gregset(const struct regset * regset,const struct regcache * regcache,int regnum,void * gregs,size_t len)110 ppc64_collect_gregset (const struct regset *regset,
111 const struct regcache *regcache,
112 int regnum, void *gregs, size_t len)
113 {
114 struct gdbarch *gdbarch = get_regcache_arch (regcache);
115 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
116 const struct ppc_reg_offsets *offsets = regset->descr;
117 size_t offset;
118 int i;
119
120 offset = offsets->r0_offset;
121 for (i = tdep->ppc_gp0_regnum;
122 i < tdep->ppc_gp0_regnum + ppc_num_gprs;
123 i++, offset += 8)
124 {
125 if (regnum == -1 || regnum == i)
126 ppc64_collect_reg (regcache, i, gregs, offset);
127 }
128
129 if (regnum == -1 || regnum == PC_REGNUM)
130 ppc64_collect_reg (regcache, PC_REGNUM, gregs, offsets->pc_offset);
131 if (regnum == -1 || regnum == tdep->ppc_ps_regnum)
132 ppc64_collect_reg (regcache, tdep->ppc_ps_regnum,
133 gregs, offsets->ps_offset);
134 if (regnum == -1 || regnum == tdep->ppc_cr_regnum)
135 ppc64_collect_reg (regcache, tdep->ppc_cr_regnum,
136 gregs, offsets->cr_offset);
137 if (regnum == -1 || regnum == tdep->ppc_lr_regnum)
138 ppc64_collect_reg (regcache, tdep->ppc_lr_regnum,
139 gregs, offsets->lr_offset);
140 if (regnum == -1 || regnum == tdep->ppc_ctr_regnum)
141 ppc64_collect_reg (regcache, tdep->ppc_ctr_regnum,
142 gregs, offsets->ctr_offset);
143 if (regnum == -1 || regnum == tdep->ppc_xer_regnum)
144 ppc64_collect_reg (regcache, tdep->ppc_xer_regnum,
145 gregs, offsets->xer_offset);
146 }
147
148 /* Core file support. */
149
150 /* Supply register REGNUM in the general-purpose register set REGSET
151 from the buffer specified by GREGS and LEN to register cache
152 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
153
154 void
ppc64obsd_supply_gregset(const struct regset * regset,struct regcache * regcache,int regnum,const void * gregs,size_t len)155 ppc64obsd_supply_gregset (const struct regset *regset,
156 struct regcache *regcache, int regnum,
157 const void *gregs, size_t len)
158 {
159 ppc64_supply_gregset (regset, regcache, regnum, gregs, len);
160 }
161
162 /* Collect register REGNUM in the general-purpose register set
163 REGSET. from register cache REGCACHE into the buffer specified by
164 GREGS and LEN. If REGNUM is -1, do this for all registers in
165 REGSET. */
166
167 void
ppc64obsd_collect_gregset(const struct regset * regset,const struct regcache * regcache,int regnum,void * gregs,size_t len)168 ppc64obsd_collect_gregset (const struct regset *regset,
169 const struct regcache *regcache, int regnum,
170 void *gregs, size_t len)
171 {
172 ppc64_collect_gregset (regset, regcache, regnum, gregs, len);
173 }
174
175 /* OpenBSD/powerpc register set. */
176
177 struct regset ppc64obsd_gregset =
178 {
179 &ppc64obsd_reg_offsets,
180 ppc64obsd_supply_gregset
181 };
182
183 struct regset ppc64obsd_fpregset =
184 {
185 &ppc64obsd_fpreg_offsets,
186 ppc_supply_fpregset
187 };
188
189 /* Return the appropriate register set for the core section identified
190 by SECT_NAME and SECT_SIZE. */
191
192 static const struct regset *
ppc64obsd_regset_from_core_section(struct gdbarch * gdbarch,const char * sect_name,size_t sect_size)193 ppc64obsd_regset_from_core_section (struct gdbarch *gdbarch,
194 const char *sect_name, size_t sect_size)
195 {
196 if (strcmp (sect_name, ".reg") == 0 && sect_size >= 304)
197 return &ppc64obsd_gregset;
198
199 if (strcmp (sect_name, ".reg2") == 0 && sect_size >= 1048)
200 return &ppc64obsd_fpregset;
201
202 return NULL;
203 }
204
205
206 /* Signal trampolines. */
207
208 /* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
209 in virtual memory. The randomness makes it somewhat tricky to
210 detect it, but fortunately we can rely on the fact that the start
211 of the sigtramp routine is page-aligned. We recognize the
212 trampoline by looking for the code that invokes the sigreturn
213 system call. The offset where we can find that code varies from
214 release to release.
215
216 By the way, the mapping mentioned above is read-only, so you cannot
217 place a breakpoint in the signal trampoline. */
218
219 /* Default page size. */
220 static const int ppc64obsd_page_size = 4096;
221
222 /* Offset for sigreturn(2). */
223 static const int ppc64obsd_sigreturn_offset[] = {
224 0x98, /* OpenBSD 3.8 */
225 0x0c, /* OpenBSD 3.2 */
226 -1
227 };
228
229 static int
ppc64obsd_sigtramp_p(struct frame_info * next_frame)230 ppc64obsd_sigtramp_p (struct frame_info *next_frame)
231 {
232 CORE_ADDR pc = frame_pc_unwind (next_frame);
233 CORE_ADDR start_pc = (pc & ~(ppc64obsd_page_size - 1));
234 const int *offset;
235 char *name;
236
237 find_pc_partial_function (pc, &name, NULL, NULL);
238 if (name)
239 return 0;
240
241 for (offset = ppc64obsd_sigreturn_offset; *offset != -1; offset++)
242 {
243 char buf[2 * PPC_INSN_SIZE];
244 unsigned long insn;
245
246 if (!safe_frame_unwind_memory (next_frame, start_pc + *offset,
247 buf, sizeof buf))
248 continue;
249
250 /* Check for "li r0,SYS_sigreturn". */
251 insn = extract_unsigned_integer (buf, PPC_INSN_SIZE);
252 if (insn != 0x38000067)
253 continue;
254
255 /* Check for "sc". */
256 insn = extract_unsigned_integer (buf + PPC_INSN_SIZE, PPC_INSN_SIZE);
257 if (insn != 0x44000002)
258 continue;
259
260 return 1;
261 }
262
263 return 0;
264 }
265
266 static struct trad_frame_cache *
ppc64obsd_sigtramp_frame_cache(struct frame_info * next_frame,void ** this_cache)267 ppc64obsd_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
268 {
269 struct gdbarch *gdbarch = get_frame_arch (next_frame);
270 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
271 struct trad_frame_cache *cache;
272 CORE_ADDR addr, base, func;
273 char buf[PPC_INSN_SIZE];
274 unsigned long insn, sigcontext_offset;
275 int i;
276
277 if (*this_cache)
278 return *this_cache;
279
280 cache = trad_frame_cache_zalloc (next_frame);
281 *this_cache = cache;
282
283 func = frame_pc_unwind (next_frame);
284 func &= ~(ppc64obsd_page_size - 1);
285 if (!safe_frame_unwind_memory (next_frame, func, buf, sizeof buf))
286 return cache;
287
288 /* Calculate the offset where we can find `struct sigcontext'. We
289 base our calculation on the amount of stack space reserved by the
290 first instruction of the signal trampoline. */
291 insn = extract_unsigned_integer (buf, PPC_INSN_SIZE);
292 sigcontext_offset = (0x10000 - (insn & 0x0000ffff)) + 8;
293
294 base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
295 addr = base + sigcontext_offset + 2 * tdep->wordsize;
296 for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize)
297 {
298 int regnum = i + tdep->ppc_gp0_regnum;
299 trad_frame_set_reg_addr (cache, regnum, addr);
300 }
301 trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, addr);
302 addr += tdep->wordsize;
303 trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, addr);
304 addr += tdep->wordsize;
305 trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, addr);
306 addr += tdep->wordsize;
307 trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, addr);
308 addr += tdep->wordsize;
309 trad_frame_set_reg_addr (cache, PC_REGNUM, addr); /* SRR0? */
310 addr += tdep->wordsize;
311
312 /* Construct the frame ID using the function start. */
313 trad_frame_set_id (cache, frame_id_build (base, func));
314
315 return cache;
316 }
317
318 static void
ppc64obsd_sigtramp_frame_this_id(struct frame_info * next_frame,void ** this_cache,struct frame_id * this_id)319 ppc64obsd_sigtramp_frame_this_id (struct frame_info *next_frame,
320 void **this_cache, struct frame_id *this_id)
321 {
322 struct trad_frame_cache *cache =
323 ppc64obsd_sigtramp_frame_cache (next_frame, this_cache);
324
325 trad_frame_get_id (cache, this_id);
326 }
327
328 static void
ppc64obsd_sigtramp_frame_prev_register(struct frame_info * next_frame,void ** this_cache,int regnum,int * optimizedp,enum lval_type * lvalp,CORE_ADDR * addrp,int * realnump,char * valuep)329 ppc64obsd_sigtramp_frame_prev_register (struct frame_info *next_frame,
330 void **this_cache, int regnum,
331 int *optimizedp, enum lval_type *lvalp,
332 CORE_ADDR *addrp, int *realnump,
333 char *valuep)
334 {
335 struct trad_frame_cache *cache =
336 ppc64obsd_sigtramp_frame_cache (next_frame, this_cache);
337
338 trad_frame_get_register (cache, next_frame, regnum,
339 optimizedp, lvalp, addrp, realnump, valuep);
340 }
341
342 static const struct frame_unwind ppc64obsd_sigtramp_frame_unwind = {
343 SIGTRAMP_FRAME,
344 ppc64obsd_sigtramp_frame_this_id,
345 ppc64obsd_sigtramp_frame_prev_register
346 };
347
348 static const struct frame_unwind *
ppc64obsd_sigtramp_frame_sniffer(struct frame_info * next_frame)349 ppc64obsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
350 {
351 if (ppc64obsd_sigtramp_p (next_frame))
352 return &ppc64obsd_sigtramp_frame_unwind;
353
354 return NULL;
355 }
356
357
358 static void
ppc64obsd_init_abi(struct gdbarch_info info,struct gdbarch * gdbarch)359 ppc64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
360 {
361 /* OpenBSD doesn't support the 128-bit `long double' from the psABI. */
362 set_gdbarch_long_double_bit (gdbarch, 64);
363 set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
364
365 /* OpenBSD currently uses a broken GCC. */
366 set_gdbarch_return_value (gdbarch, ppc_sysv_abi_broken_return_value);
367
368 /* OpenBSD uses SVR4-style shared libraries. */
369 set_solib_svr4_fetch_link_map_offsets
370 (gdbarch, svr4_lp64_fetch_link_map_offsets);
371
372 set_gdbarch_regset_from_core_section
373 (gdbarch, ppc64obsd_regset_from_core_section);
374
375 frame_unwind_append_sniffer (gdbarch, ppc64obsd_sigtramp_frame_sniffer);
376 }
377
378
379 /* OpenBSD uses uses the traditional NetBSD core file format, even for
380 ports that use ELF. */
381 #define GDB_OSABI_NETBSD_CORE GDB_OSABI_OPENBSD_ELF
382
383 static enum gdb_osabi
ppc64obsd_core_osabi_sniffer(bfd * abfd)384 ppc64obsd_core_osabi_sniffer (bfd *abfd)
385 {
386 if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
387 return GDB_OSABI_NETBSD_CORE;
388
389 return GDB_OSABI_UNKNOWN;
390 }
391
392
393 /* Provide a prototype to silence -Wmissing-prototypes. */
394 void _initialize_ppc64obsd_tdep (void);
395
396 void
_initialize_ppc64obsd_tdep(void)397 _initialize_ppc64obsd_tdep (void)
398 {
399 /* BFD doesn't set a flavour for NetBSD style a.out core files. */
400 gdbarch_register_osabi_sniffer (bfd_arch_powerpc, bfd_target_unknown_flavour,
401 ppc64obsd_core_osabi_sniffer);
402
403 #if 0
404 gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_OPENBSD_ELF,
405 ppc64obsd_init_abi);
406 #endif
407 gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc64,
408 GDB_OSABI_OPENBSD_ELF, ppc64obsd_init_abi);
409
410 /* Avoid initializing the register offsets again if they were
411 already initailized by ppc64obsd-nat.c. */
412 if (ppc64obsd_reg_offsets.pc_offset == 0)
413 {
414 /* General-purpose registers. */
415 ppc64obsd_reg_offsets.r0_offset = 0;
416 ppc64obsd_reg_offsets.pc_offset = 288;
417 ppc64obsd_reg_offsets.ps_offset = 296;
418 ppc64obsd_reg_offsets.cr_offset = 264;
419 ppc64obsd_reg_offsets.lr_offset = 256;
420 ppc64obsd_reg_offsets.ctr_offset = 280;
421 ppc64obsd_reg_offsets.xer_offset = 272;
422 ppc64obsd_reg_offsets.mq_offset = -1;
423
424 /* Floating-point registers. */
425 ppc64obsd_reg_offsets.f0_offset = -1;
426 ppc64obsd_reg_offsets.fpscr_offset = -1;
427
428 /* AltiVec registers. */
429 ppc64obsd_reg_offsets.vr0_offset = -1;
430 ppc64obsd_reg_offsets.vscr_offset = -1;
431 ppc64obsd_reg_offsets.vrsave_offset = -1;
432 }
433
434 if (ppc64obsd_fpreg_offsets.fpscr_offset == 0)
435 {
436 /* Floating-point registers. */
437 ppc64obsd_reg_offsets.f0_offset = -1;
438 ppc64obsd_reg_offsets.fpscr_offset = -1;
439 }
440 }
441