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
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
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
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
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
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
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 *
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
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 *
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
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
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 *
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
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
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
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