Simplify tui_show_disassem
[external/binutils.git] / gdb / ppc-obsd-tdep.c
1 /* Target-dependent code for OpenBSD/powerpc.
2
3    Copyright (C) 2004-2019 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 \f
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 \f
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 \f
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
265 _initialize_ppcobsd_tdep (void)
266 {
267   gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_OPENBSD,
268                           ppcobsd_init_abi);
269   gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_OPENBSD,
270                           ppcobsd_init_abi);
271
272   /* Avoid initializing the register offsets again if they were
273      already initialized by ppcobsd-nat.c.  */
274   if (ppcobsd_reg_offsets.pc_offset == 0)
275     {
276       /* General-purpose registers.  */
277       ppcobsd_reg_offsets.r0_offset = 0;
278       ppcobsd_reg_offsets.gpr_size = 4;
279       ppcobsd_reg_offsets.xr_size = 4;
280       ppcobsd_reg_offsets.pc_offset = 384;
281       ppcobsd_reg_offsets.ps_offset = 388;
282       ppcobsd_reg_offsets.cr_offset = 392;
283       ppcobsd_reg_offsets.lr_offset = 396;
284       ppcobsd_reg_offsets.ctr_offset = 400;
285       ppcobsd_reg_offsets.xer_offset = 404;
286       ppcobsd_reg_offsets.mq_offset = 408;
287
288       /* Floating-point registers.  */
289       ppcobsd_reg_offsets.f0_offset = 128;
290       ppcobsd_reg_offsets.fpscr_offset = -1;
291
292     }
293
294   if (ppcobsd_fpreg_offsets.fpscr_offset == 0)
295     {
296       /* Floating-point registers.  */
297       ppcobsd_reg_offsets.f0_offset = 0;
298       ppcobsd_reg_offsets.fpscr_offset = 256;
299       ppcobsd_reg_offsets.fpscr_size = 4;
300     }
301 }