gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gdb / ppc-obsd-tdep.c
CommitLineData
d195bc9f
MK
1/* Target-dependent code for OpenBSD/powerpc.
2
b811d2c2 3 Copyright (C) 2004-2020 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
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
d195bc9f
MK
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
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
d195bc9f
MK
19
20#include "defs.h"
21#include "arch-utils.h"
0dbe1904
MK
22#include "frame.h"
23#include "frame-unwind.h"
e6bb342a 24#include "gdbtypes.h"
d195bc9f
MK
25#include "osabi.h"
26#include "regcache.h"
27#include "regset.h"
0dbe1904 28#include "symtab.h"
18b2ae85 29#include "trad-frame.h"
d195bc9f 30
d195bc9f 31#include "ppc-tdep.h"
03b62bbb 32#include "ppc-obsd-tdep.h"
d195bc9f
MK
33#include "solib-svr4.h"
34
35/* Register offsets from <machine/reg.h>. */
36struct ppc_reg_offsets ppcobsd_reg_offsets;
8599da2d 37struct ppc_reg_offsets ppcobsd_fpreg_offsets;
d195bc9f
MK
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
46void
47ppcobsd_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
0df8b418 56 REGSET, from register cache REGCACHE into the buffer specified by
d195bc9f
MK
57 GREGS and LEN. If REGNUM is -1, do this for all registers in
58 REGSET. */
59
60void
61ppcobsd_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
5d6210f0 69/* OpenBSD/powerpc register set. */
d195bc9f 70
3ca7dae4 71const struct regset ppcobsd_gregset =
d195bc9f
MK
72{
73 &ppcobsd_reg_offsets,
74 ppcobsd_supply_gregset
75};
76
3ca7dae4 77const struct regset ppcobsd_fpregset =
8599da2d
MK
78{
79 &ppcobsd_fpreg_offsets,
80 ppc_supply_fpregset
81};
82
23ea9aeb 83/* Iterate over core file register note sections. */
d195bc9f 84
23ea9aeb
AA
85static void
86ppcobsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
87 iterate_over_regset_sections_cb *cb,
88 void *cb_data,
89 const struct regcache *regcache)
d195bc9f 90{
a616bb94 91 cb (".reg", 412, 412, &ppcobsd_gregset, NULL, cb_data);
d195bc9f
MK
92}
93\f
94
18b2ae85
MK
95/* Signal trampolines. */
96
0dbe1904
MK
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. */
109static const int ppcobsd_page_size = 4096;
110
111/* Offset for sigreturn(2). */
112static const int ppcobsd_sigreturn_offset[] = {
113 0x98, /* OpenBSD 3.8 */
114 0x0c, /* OpenBSD 3.2 */
115 -1
116};
117
118static int
1af5d7ce
UW
119ppcobsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
120 struct frame_info *this_frame,
121 void **this_cache)
0dbe1904 122{
e17a4113
UW
123 struct gdbarch *gdbarch = get_frame_arch (this_frame);
124 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
1af5d7ce 125 CORE_ADDR pc = get_frame_pc (this_frame);
0dbe1904
MK
126 CORE_ADDR start_pc = (pc & ~(ppcobsd_page_size - 1));
127 const int *offset;
2c02bd72 128 const char *name;
0dbe1904
MK
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
1af5d7ce 139 if (!safe_frame_unwind_memory (this_frame, start_pc + *offset,
0dbe1904
MK
140 buf, sizeof buf))
141 continue;
142
143 /* Check for "li r0,SYS_sigreturn". */
e17a4113 144 insn = extract_unsigned_integer (buf, PPC_INSN_SIZE, byte_order);
0dbe1904
MK
145 if (insn != 0x38000067)
146 continue;
147
148 /* Check for "sc". */
e17a4113
UW
149 insn = extract_unsigned_integer (buf + PPC_INSN_SIZE,
150 PPC_INSN_SIZE, byte_order);
0dbe1904
MK
151 if (insn != 0x44000002)
152 continue;
153
154 return 1;
155 }
156
157 return 0;
158}
159
160static struct trad_frame_cache *
1af5d7ce 161ppcobsd_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache)
18b2ae85 162{
1af5d7ce 163 struct gdbarch *gdbarch = get_frame_arch (this_frame);
18b2ae85 164 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
e17a4113 165 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
0dbe1904
MK
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;
18b2ae85
MK
170 int i;
171
0dbe1904 172 if (*this_cache)
19ba03f4 173 return (struct trad_frame_cache *) *this_cache;
0dbe1904 174
1af5d7ce 175 cache = trad_frame_cache_zalloc (this_frame);
0dbe1904
MK
176 *this_cache = cache;
177
1af5d7ce 178 func = get_frame_pc (this_frame);
0dbe1904 179 func &= ~(ppcobsd_page_size - 1);
1af5d7ce 180 if (!safe_frame_unwind_memory (this_frame, func, buf, sizeof buf))
0dbe1904
MK
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. */
e17a4113 186 insn = extract_unsigned_integer (buf, PPC_INSN_SIZE, byte_order);
0dbe1904
MK
187 sigcontext_offset = (0x10000 - (insn & 0x0000ffff)) + 8;
188
1af5d7ce 189 base = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch));
0dbe1904 190 addr = base + sigcontext_offset + 2 * tdep->wordsize;
18b2ae85
MK
191 for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize)
192 {
193 int regnum = i + tdep->ppc_gp0_regnum;
0dbe1904 194 trad_frame_set_reg_addr (cache, regnum, addr);
18b2ae85 195 }
0dbe1904 196 trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, addr);
18b2ae85 197 addr += tdep->wordsize;
0dbe1904 198 trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, addr);
18b2ae85 199 addr += tdep->wordsize;
0dbe1904 200 trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, addr);
18b2ae85 201 addr += tdep->wordsize;
0dbe1904 202 trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, addr);
18b2ae85 203 addr += tdep->wordsize;
40a6adc1 204 trad_frame_set_reg_addr (cache, gdbarch_pc_regnum (gdbarch), addr);
0df8b418 205 /* SRR0? */
18b2ae85
MK
206 addr += tdep->wordsize;
207
208 /* Construct the frame ID using the function start. */
0dbe1904
MK
209 trad_frame_set_id (cache, frame_id_build (base, func));
210
211 return cache;
18b2ae85
MK
212}
213
0dbe1904 214static void
1af5d7ce 215ppcobsd_sigtramp_frame_this_id (struct frame_info *this_frame,
0dbe1904
MK
216 void **this_cache, struct frame_id *this_id)
217{
218 struct trad_frame_cache *cache =
1af5d7ce 219 ppcobsd_sigtramp_frame_cache (this_frame, this_cache);
0dbe1904
MK
220
221 trad_frame_get_id (cache, this_id);
222}
223
1af5d7ce
UW
224static struct value *
225ppcobsd_sigtramp_frame_prev_register (struct frame_info *this_frame,
226 void **this_cache, int regnum)
18b2ae85 227{
0dbe1904 228 struct trad_frame_cache *cache =
1af5d7ce 229 ppcobsd_sigtramp_frame_cache (this_frame, this_cache);
0dbe1904 230
1af5d7ce 231 return trad_frame_get_register (cache, this_frame, regnum);
0dbe1904
MK
232}
233
234static const struct frame_unwind ppcobsd_sigtramp_frame_unwind = {
18b2ae85 235 SIGTRAMP_FRAME,
8fbca658 236 default_frame_unwind_stop_reason,
0dbe1904 237 ppcobsd_sigtramp_frame_this_id,
1af5d7ce
UW
238 ppcobsd_sigtramp_frame_prev_register,
239 NULL,
240 ppcobsd_sigtramp_frame_sniffer
18b2ae85 241};
18b2ae85 242\f
5d6210f0 243
d195bc9f
MK
244static void
245ppcobsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
246{
5a49dfd0
MK
247 /* OpenBSD doesn't support the 128-bit `long double' from the psABI. */
248 set_gdbarch_long_double_bit (gdbarch, 64);
8da61cc4 249 set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
5a49dfd0 250
a86c5ab2
MK
251 /* OpenBSD currently uses a broken GCC. */
252 set_gdbarch_return_value (gdbarch, ppc_sysv_abi_broken_return_value);
253
d195bc9f 254 /* OpenBSD uses SVR4-style shared libraries. */
d195bc9f
MK
255 set_solib_svr4_fetch_link_map_offsets
256 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
257
23ea9aeb
AA
258 set_gdbarch_iterate_over_regset_sections
259 (gdbarch, ppcobsd_iterate_over_regset_sections);
18b2ae85 260
1af5d7ce 261 frame_unwind_append_unwinder (gdbarch, &ppcobsd_sigtramp_frame_unwind);
d195bc9f 262}
d195bc9f 263
6c265988 264void _initialize_ppcobsd_tdep ();
d195bc9f 265void
6c265988 266_initialize_ppcobsd_tdep ()
d195bc9f 267{
1736a7bd 268 gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_OPENBSD,
5d6210f0 269 ppcobsd_init_abi);
1736a7bd 270 gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_OPENBSD,
d195bc9f
MK
271 ppcobsd_init_abi);
272
273 /* Avoid initializing the register offsets again if they were
26c4b26f 274 already initialized by ppcobsd-nat.c. */
d195bc9f
MK
275 if (ppcobsd_reg_offsets.pc_offset == 0)
276 {
277 /* General-purpose registers. */
278 ppcobsd_reg_offsets.r0_offset = 0;
f2db237a
AM
279 ppcobsd_reg_offsets.gpr_size = 4;
280 ppcobsd_reg_offsets.xr_size = 4;
d195bc9f
MK
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
d195bc9f 293 }
8599da2d
MK
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;
f2db237a 300 ppcobsd_reg_offsets.fpscr_size = 4;
8599da2d 301 }
d195bc9f 302}
This page took 1.547662 seconds and 4 git commands to generate.