xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/ppc-obsd-tdep.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* Target-dependent code for OpenBSD/powerpc.
2 
3    Copyright (C) 2004-2020 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 3 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, see <http://www.gnu.org/licenses/>.  */
19 
20 #include "defs.h"
21 #include "arch-utils.h"
22 #include "frame.h"
23 #include "frame-unwind.h"
24 #include "gdbtypes.h"
25 #include "osabi.h"
26 #include "regcache.h"
27 #include "regset.h"
28 #include "symtab.h"
29 #include "trad-frame.h"
30 
31 #include "ppc-tdep.h"
32 #include "ppc-obsd-tdep.h"
33 #include "solib-svr4.h"
34 
35 /* Register offsets from <machine/reg.h>.  */
36 struct ppc_reg_offsets ppcobsd_reg_offsets;
37 struct ppc_reg_offsets ppcobsd_fpreg_offsets;
38 
39 
40 /* Core file support.  */
41 
42 /* Supply register REGNUM in the general-purpose register set REGSET
43    from the buffer specified by GREGS and LEN to register cache
44    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
45 
46 void
47 ppcobsd_supply_gregset (const struct regset *regset,
48 			struct regcache *regcache, int regnum,
49 			const void *gregs, size_t len)
50 {
51   ppc_supply_gregset (regset, regcache, regnum, gregs, len);
52   ppc_supply_fpregset (regset, regcache, regnum, gregs, len);
53 }
54 
55 /* Collect register REGNUM in the general-purpose register set
56    REGSET, from register cache REGCACHE into the buffer specified by
57    GREGS and LEN.  If REGNUM is -1, do this for all registers in
58    REGSET.  */
59 
60 void
61 ppcobsd_collect_gregset (const struct regset *regset,
62 			 const struct regcache *regcache, int regnum,
63 			 void *gregs, size_t len)
64 {
65   ppc_collect_gregset (regset, regcache, regnum, gregs, len);
66   ppc_collect_fpregset (regset, regcache, regnum, gregs, len);
67 }
68 
69 /* OpenBSD/powerpc register set.  */
70 
71 const struct regset ppcobsd_gregset =
72 {
73   &ppcobsd_reg_offsets,
74   ppcobsd_supply_gregset
75 };
76 
77 const struct regset ppcobsd_fpregset =
78 {
79   &ppcobsd_fpreg_offsets,
80   ppc_supply_fpregset
81 };
82 
83 /* Iterate over core file register note sections.  */
84 
85 static void
86 ppcobsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
87 				      iterate_over_regset_sections_cb *cb,
88 				      void *cb_data,
89 				      const struct regcache *regcache)
90 {
91   cb (".reg", 412, 412, &ppcobsd_gregset, NULL, cb_data);
92 }
93 
94 
95 /* Signal trampolines.  */
96 
97 /* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
98    in virtual memory.  The randomness makes it somewhat tricky to
99    detect it, but fortunately we can rely on the fact that the start
100    of the sigtramp routine is page-aligned.  We recognize the
101    trampoline by looking for the code that invokes the sigreturn
102    system call.  The offset where we can find that code varies from
103    release to release.
104 
105    By the way, the mapping mentioned above is read-only, so you cannot
106    place a breakpoint in the signal trampoline.  */
107 
108 /* Default page size.  */
109 static const int ppcobsd_page_size = 4096;
110 
111 /* Offset for sigreturn(2).  */
112 static const int ppcobsd_sigreturn_offset[] = {
113   0x98,				/* OpenBSD 3.8 */
114   0x0c,				/* OpenBSD 3.2 */
115   -1
116 };
117 
118 static int
119 ppcobsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
120 				struct frame_info *this_frame,
121 				void **this_cache)
122 {
123   struct gdbarch *gdbarch = get_frame_arch (this_frame);
124   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
125   CORE_ADDR pc = get_frame_pc (this_frame);
126   CORE_ADDR start_pc = (pc & ~(ppcobsd_page_size - 1));
127   const int *offset;
128   const char *name;
129 
130   find_pc_partial_function (pc, &name, NULL, NULL);
131   if (name)
132     return 0;
133 
134   for (offset = ppcobsd_sigreturn_offset; *offset != -1; offset++)
135     {
136       gdb_byte buf[2 * PPC_INSN_SIZE];
137       unsigned long insn;
138 
139       if (!safe_frame_unwind_memory (this_frame, start_pc + *offset,
140 				     buf, sizeof buf))
141 	continue;
142 
143       /* Check for "li r0,SYS_sigreturn".  */
144       insn = extract_unsigned_integer (buf, PPC_INSN_SIZE, byte_order);
145       if (insn != 0x38000067)
146 	continue;
147 
148       /* Check for "sc".  */
149       insn = extract_unsigned_integer (buf + PPC_INSN_SIZE,
150 				       PPC_INSN_SIZE, byte_order);
151       if (insn != 0x44000002)
152 	continue;
153 
154       return 1;
155     }
156 
157   return 0;
158 }
159 
160 static struct trad_frame_cache *
161 ppcobsd_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache)
162 {
163   struct gdbarch *gdbarch = get_frame_arch (this_frame);
164   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
165   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
166   struct trad_frame_cache *cache;
167   CORE_ADDR addr, base, func;
168   gdb_byte buf[PPC_INSN_SIZE];
169   unsigned long insn, sigcontext_offset;
170   int i;
171 
172   if (*this_cache)
173     return (struct trad_frame_cache *) *this_cache;
174 
175   cache = trad_frame_cache_zalloc (this_frame);
176   *this_cache = cache;
177 
178   func = get_frame_pc (this_frame);
179   func &= ~(ppcobsd_page_size - 1);
180   if (!safe_frame_unwind_memory (this_frame, func, buf, sizeof buf))
181     return cache;
182 
183   /* Calculate the offset where we can find `struct sigcontext'.  We
184      base our calculation on the amount of stack space reserved by the
185      first instruction of the signal trampoline.  */
186   insn = extract_unsigned_integer (buf, PPC_INSN_SIZE, byte_order);
187   sigcontext_offset = (0x10000 - (insn & 0x0000ffff)) + 8;
188 
189   base = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch));
190   addr = base + sigcontext_offset + 2 * tdep->wordsize;
191   for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize)
192     {
193       int regnum = i + tdep->ppc_gp0_regnum;
194       trad_frame_set_reg_addr (cache, regnum, addr);
195     }
196   trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, addr);
197   addr += tdep->wordsize;
198   trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, addr);
199   addr += tdep->wordsize;
200   trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, addr);
201   addr += tdep->wordsize;
202   trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, addr);
203   addr += tdep->wordsize;
204   trad_frame_set_reg_addr (cache, gdbarch_pc_regnum (gdbarch), addr);
205   /* SRR0?  */
206   addr += tdep->wordsize;
207 
208   /* Construct the frame ID using the function start.  */
209   trad_frame_set_id (cache, frame_id_build (base, func));
210 
211   return cache;
212 }
213 
214 static void
215 ppcobsd_sigtramp_frame_this_id (struct frame_info *this_frame,
216 				void **this_cache, struct frame_id *this_id)
217 {
218   struct trad_frame_cache *cache =
219     ppcobsd_sigtramp_frame_cache (this_frame, this_cache);
220 
221   trad_frame_get_id (cache, this_id);
222 }
223 
224 static struct value *
225 ppcobsd_sigtramp_frame_prev_register (struct frame_info *this_frame,
226 				      void **this_cache, int regnum)
227 {
228   struct trad_frame_cache *cache =
229     ppcobsd_sigtramp_frame_cache (this_frame, this_cache);
230 
231   return trad_frame_get_register (cache, this_frame, regnum);
232 }
233 
234 static const struct frame_unwind ppcobsd_sigtramp_frame_unwind = {
235   SIGTRAMP_FRAME,
236   default_frame_unwind_stop_reason,
237   ppcobsd_sigtramp_frame_this_id,
238   ppcobsd_sigtramp_frame_prev_register,
239   NULL,
240   ppcobsd_sigtramp_frame_sniffer
241 };
242 
243 
244 static void
245 ppcobsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
246 {
247   /* OpenBSD doesn't support the 128-bit `long double' from the psABI.  */
248   set_gdbarch_long_double_bit (gdbarch, 64);
249   set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
250 
251   /* OpenBSD currently uses a broken GCC.  */
252   set_gdbarch_return_value (gdbarch, ppc_sysv_abi_broken_return_value);
253 
254   /* OpenBSD uses SVR4-style shared libraries.  */
255   set_solib_svr4_fetch_link_map_offsets
256     (gdbarch, svr4_ilp32_fetch_link_map_offsets);
257 
258   set_gdbarch_iterate_over_regset_sections
259     (gdbarch, ppcobsd_iterate_over_regset_sections);
260 
261   frame_unwind_append_unwinder (gdbarch, &ppcobsd_sigtramp_frame_unwind);
262 }
263 
264 void _initialize_ppcobsd_tdep ();
265 void
266 _initialize_ppcobsd_tdep ()
267 {
268   gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_OPENBSD,
269 			  ppcobsd_init_abi);
270   gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_OPENBSD,
271 			  ppcobsd_init_abi);
272 
273   /* Avoid initializing the register offsets again if they were
274      already initialized by ppcobsd-nat.c.  */
275   if (ppcobsd_reg_offsets.pc_offset == 0)
276     {
277       /* General-purpose registers.  */
278       ppcobsd_reg_offsets.r0_offset = 0;
279       ppcobsd_reg_offsets.gpr_size = 4;
280       ppcobsd_reg_offsets.xr_size = 4;
281       ppcobsd_reg_offsets.pc_offset = 384;
282       ppcobsd_reg_offsets.ps_offset = 388;
283       ppcobsd_reg_offsets.cr_offset = 392;
284       ppcobsd_reg_offsets.lr_offset = 396;
285       ppcobsd_reg_offsets.ctr_offset = 400;
286       ppcobsd_reg_offsets.xer_offset = 404;
287       ppcobsd_reg_offsets.mq_offset = 408;
288 
289       /* Floating-point registers.  */
290       ppcobsd_reg_offsets.f0_offset = 128;
291       ppcobsd_reg_offsets.fpscr_offset = -1;
292 
293     }
294 
295   if (ppcobsd_fpreg_offsets.fpscr_offset == 0)
296     {
297       /* Floating-point registers.  */
298       ppcobsd_reg_offsets.f0_offset = 0;
299       ppcobsd_reg_offsets.fpscr_offset = 256;
300       ppcobsd_reg_offsets.fpscr_size = 4;
301     }
302 }
303