gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gdb / alpha-nbsd-tdep.c
CommitLineData
789f3b5f
MK
1/* Target-dependent code for NetBSD/alpha.
2
b811d2c2 3 Copyright (C) 2002-2020 Free Software Foundation, Inc.
2031c21a 4
da8ca43d
JT
5 Contributed by Wasabi Systems, Inc.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
a9762ec7 11 the Free Software Foundation; either version 3 of the License, or
da8ca43d
JT
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
a9762ec7 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
da8ca43d
JT
21
22#include "defs.h"
2ca8ae21 23#include "frame.h"
3beabdb2
MK
24#include "gdbcore.h"
25#include "osabi.h"
8513dd2d 26#include "regcache.h"
3beabdb2 27#include "regset.h"
4de283e4
TT
28#include "value.h"
29
30#include "alpha-tdep.h"
31#include "alpha-bsd-tdep.h"
32#include "nbsd-tdep.h"
527ca6bb 33#include "solib-svr4.h"
effa26a9 34#include "target.h"
8513dd2d 35
3beabdb2
MK
36/* Core file support. */
37
3beabdb2
MK
38/* Sizeof `struct reg' in <machine/reg.h>. */
39#define ALPHANBSD_SIZEOF_GREGS (32 * 8)
40
41/* Sizeof `struct fpreg' in <machine/reg.h. */
42#define ALPHANBSD_SIZEOF_FPREGS ((32 * 8) + 8)
43
44/* Supply register REGNUM from the buffer specified by FPREGS and LEN
45 in the floating-point register set REGSET to register cache
46 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
47
8513dd2d 48static void
3beabdb2
MK
49alphanbsd_supply_fpregset (const struct regset *regset,
50 struct regcache *regcache,
51 int regnum, const void *fpregs, size_t len)
8513dd2d 52{
9a3c8263 53 const gdb_byte *regs = (const gdb_byte *) fpregs;
3beabdb2
MK
54 int i;
55
56 gdb_assert (len >= ALPHANBSD_SIZEOF_FPREGS);
57
58 for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; i++)
59 {
60 if (regnum == i || regnum == -1)
73e1c03f 61 regcache->raw_supply (i, regs + (i - ALPHA_FP0_REGNUM) * 8);
3beabdb2
MK
62 }
63
64 if (regnum == ALPHA_FPCR_REGNUM || regnum == -1)
73e1c03f 65 regcache->raw_supply (ALPHA_FPCR_REGNUM, regs + 32 * 8);
3beabdb2
MK
66}
67
3beabdb2
MK
68/* Supply register REGNUM from the buffer specified by GREGS and LEN
69 in the general-purpose register set REGSET to register cache
70 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
71
72static void
73alphanbsd_aout_supply_gregset (const struct regset *regset,
74 struct regcache *regcache,
75 int regnum, const void *gregs, size_t len)
76{
9a3c8263 77 const gdb_byte *regs = (const gdb_byte *) gregs;
3beabdb2
MK
78 int i;
79
80 /* Table to map a GDB register number to a trapframe register index. */
8513dd2d
JT
81 static const int regmap[] =
82 {
83 0, 1, 2, 3,
84 4, 5, 6, 7,
85 8, 9, 10, 11,
86 12, 13, 14, 15,
87 30, 31, 32, 16,
88 17, 18, 19, 20,
89 21, 22, 23, 24,
90 25, 29, 26
91 };
8513dd2d 92
3beabdb2 93 gdb_assert (len >= ALPHANBSD_SIZEOF_GREGS);
8513dd2d 94
3beabdb2 95 for (i = 0; i < ARRAY_SIZE(regmap); i++)
8513dd2d 96 {
3beabdb2 97 if (regnum == i || regnum == -1)
73e1c03f 98 regcache->raw_supply (i, regs + regmap[i] * 8);
8513dd2d
JT
99 }
100
3beabdb2 101 if (regnum == ALPHA_PC_REGNUM || regnum == -1)
73e1c03f 102 regcache->raw_supply (ALPHA_PC_REGNUM, regs + 31 * 8);
8513dd2d 103
3beabdb2 104 if (len >= ALPHANBSD_SIZEOF_GREGS + ALPHANBSD_SIZEOF_FPREGS)
8513dd2d 105 {
3beabdb2
MK
106 regs += ALPHANBSD_SIZEOF_GREGS;
107 len -= ALPHANBSD_SIZEOF_GREGS;
108 alphanbsd_supply_fpregset (regset, regcache, regnum, regs, len);
8513dd2d
JT
109 }
110}
111
dff2166e
AA
112/* Supply register REGNUM from the buffer specified by GREGS and LEN
113 in the general-purpose register set REGSET to register cache
114 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
115
116static void
117alphanbsd_supply_gregset (const struct regset *regset,
118 struct regcache *regcache,
119 int regnum, const void *gregs, size_t len)
120{
9a3c8263 121 const gdb_byte *regs = (const gdb_byte *) gregs;
dff2166e
AA
122 int i;
123
124 if (len >= ALPHANBSD_SIZEOF_GREGS + ALPHANBSD_SIZEOF_FPREGS)
125 {
126 alphanbsd_aout_supply_gregset (regset, regcache, regnum, gregs, len);
127 return;
128 }
129
130 for (i = 0; i < ALPHA_ZERO_REGNUM; i++)
131 {
132 if (regnum == i || regnum == -1)
73e1c03f 133 regcache->raw_supply (i, regs + i * 8);
dff2166e
AA
134 }
135
136 if (regnum == ALPHA_PC_REGNUM || regnum == -1)
73e1c03f 137 regcache->raw_supply (ALPHA_PC_REGNUM, regs + 31 * 8);
dff2166e
AA
138}
139
3beabdb2
MK
140/* NetBSD/alpha register sets. */
141
3ca7dae4 142static const struct regset alphanbsd_gregset =
8513dd2d 143{
3beabdb2 144 NULL,
f962539a
AA
145 alphanbsd_supply_gregset,
146 NULL,
147 REGSET_VARIABLE_SIZE
8513dd2d
JT
148};
149
3ca7dae4 150static const struct regset alphanbsd_fpregset =
8513dd2d 151{
3beabdb2
MK
152 NULL,
153 alphanbsd_supply_fpregset
8513dd2d 154};
da8ca43d 155
dff2166e 156/* Iterate over supported core file register note sections. */
3beabdb2 157
dff2166e
AA
158void
159alphanbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
160 iterate_over_regset_sections_cb *cb,
161 void *cb_data,
162 const struct regcache *regcache)
3beabdb2 163{
a616bb94
AH
164 cb (".reg", ALPHANBSD_SIZEOF_GREGS, ALPHANBSD_SIZEOF_GREGS,
165 &alphanbsd_gregset, NULL, cb_data);
166 cb (".reg2", ALPHANBSD_SIZEOF_FPREGS, ALPHANBSD_SIZEOF_FPREGS,
167 &alphanbsd_fpregset, NULL, cb_data);
3beabdb2 168}
3beabdb2
MK
169\f
170
171/* Signal trampolines. */
172
da8ca43d
JT
173/* Under NetBSD/alpha, signal handler invocations can be identified by the
174 designated code sequence that is used to return from a signal handler.
175 In particular, the return address of a signal handler points to the
176 following code sequence:
177
178 ldq a0, 0(sp)
179 lda sp, 16(sp)
180 lda v0, 295(zero) # __sigreturn14
181 call_pal callsys
182
183 Each instruction has a unique encoding, so we simply attempt to match
184 the instruction the PC is pointing to with any of the above instructions.
185 If there is a hit, we know the offset to the start of the designated
186 sequence and can then check whether we really are executing in the
187 signal trampoline. If not, -1 is returned, otherwise the offset from the
188 start of the return sequence is returned. */
948f8e3d 189static const gdb_byte sigtramp_retcode[] =
da8ca43d 190{
cfef91e4
JT
191 0x00, 0x00, 0x1e, 0xa6, /* ldq a0, 0(sp) */
192 0x10, 0x00, 0xde, 0x23, /* lda sp, 16(sp) */
193 0x27, 0x01, 0x1f, 0x20, /* lda v0, 295(zero) */
194 0x83, 0x00, 0x00, 0x00, /* call_pal callsys */
da8ca43d 195};
cfef91e4
JT
196#define RETCODE_NWORDS 4
197#define RETCODE_SIZE (RETCODE_NWORDS * 4)
da8ca43d 198
b0ca8573 199static LONGEST
e17a4113 200alphanbsd_sigtramp_offset (struct gdbarch *gdbarch, CORE_ADDR pc)
da8ca43d 201{
948f8e3d 202 gdb_byte ret[RETCODE_SIZE], w[4];
da8ca43d
JT
203 LONGEST off;
204 int i;
205
948f8e3d 206 if (target_read_memory (pc, w, 4) != 0)
da8ca43d
JT
207 return -1;
208
209 for (i = 0; i < RETCODE_NWORDS; i++)
210 {
cfef91e4 211 if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0)
da8ca43d
JT
212 break;
213 }
214 if (i == RETCODE_NWORDS)
215 return (-1);
216
217 off = i * 4;
218 pc -= off;
219
948f8e3d 220 if (target_read_memory (pc, ret, sizeof (ret)) != 0)
da8ca43d
JT
221 return -1;
222
cfef91e4 223 if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0)
da8ca43d
JT
224 return off;
225
226 return -1;
227}
228
6c72f9f9 229static int
e17a4113 230alphanbsd_pc_in_sigtramp (struct gdbarch *gdbarch,
2c02bd72 231 CORE_ADDR pc, const char *func_name)
6c72f9f9 232{
3d9b49b0 233 return (nbsd_pc_in_sigtramp (pc, func_name)
e17a4113 234 || alphanbsd_sigtramp_offset (gdbarch, pc) >= 0);
6c72f9f9
JT
235}
236
2ca8ae21
JT
237static CORE_ADDR
238alphanbsd_sigcontext_addr (struct frame_info *frame)
239{
240 /* FIXME: This is not correct for all versions of NetBSD/alpha.
241 We will probably need to disassemble the trampoline to figure
242 out which trampoline frame type we have. */
94afd7a6
UW
243 if (!get_next_frame (frame))
244 return 0;
245 return get_frame_base (get_next_frame (frame));
2ca8ae21 246}
b0ca8573 247\f
2ca8ae21 248
da8ca43d
JT
249static void
250alphanbsd_init_abi (struct gdbarch_info info,
251 struct gdbarch *gdbarch)
252{
253 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
254
baa490c4
RH
255 /* Hook into the DWARF CFI frame unwinder. */
256 alpha_dwarf2_init_abi (info, gdbarch);
257
258 /* Hook into the MDEBUG frame unwinder. */
259 alpha_mdebug_init_abi (info, gdbarch);
79743962
KR
260
261 nbsd_init_abi (info, gdbarch);
baa490c4 262
da8ca43d
JT
263 /* NetBSD/alpha does not provide single step support via ptrace(2); we
264 must use software single-stepping. */
265 set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
266
789f3b5f
MK
267 /* NetBSD/alpha has SVR4-style shared libraries. */
268 set_solib_svr4_fetch_link_map_offsets
269 (gdbarch, svr4_lp64_fetch_link_map_offsets);
da8ca43d
JT
270
271 tdep->dynamic_sigtramp_offset = alphanbsd_sigtramp_offset;
f2524b93 272 tdep->pc_in_sigtramp = alphanbsd_pc_in_sigtramp;
2ca8ae21 273 tdep->sigcontext_addr = alphanbsd_sigcontext_addr;
accc6d1f
JT
274
275 tdep->jb_pc = 2;
276 tdep->jb_elt_size = 8;
3beabdb2 277
dff2166e
AA
278 set_gdbarch_iterate_over_regset_sections
279 (gdbarch, alphanbsd_iterate_over_regset_sections);
3beabdb2 280}
3beabdb2
MK
281\f
282
6c265988 283void _initialize_alphanbsd_tdep ();
da8ca43d 284void
6c265988 285_initialize_alphanbsd_tdep ()
da8ca43d 286{
1736a7bd
PA
287 /* Even though NetBSD/alpha used ELF since day one, it used the
288 traditional a.out-style core dump format before NetBSD 1.6, but
289 we don't support those. */
290 gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD,
70f80edf 291 alphanbsd_init_abi);
da8ca43d 292}
This page took 1.060878 seconds and 4 git commands to generate.