Automatic date update in version.in
[deliverable/binutils-gdb.git] / gdb / alpha-nbsd-tdep.c
CommitLineData
789f3b5f
MK
1/* Target-dependent code for NetBSD/alpha.
2
e2882c85 3 Copyright (C) 2002-2018 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"
da8ca43d 28#include "value.h"
da8ca43d
JT
29
30#include "alpha-tdep.h"
03b62bbb 31#include "alpha-bsd-tdep.h"
ea5bc2a6 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{
dff2166e
AA
164 cb (".reg", ALPHANBSD_SIZEOF_GREGS, &alphanbsd_gregset, NULL, cb_data);
165 cb (".reg2", ALPHANBSD_SIZEOF_FPREGS, &alphanbsd_fpregset, NULL, cb_data);
3beabdb2 166}
3beabdb2
MK
167\f
168
169/* Signal trampolines. */
170
da8ca43d
JT
171/* Under NetBSD/alpha, signal handler invocations can be identified by the
172 designated code sequence that is used to return from a signal handler.
173 In particular, the return address of a signal handler points to the
174 following code sequence:
175
176 ldq a0, 0(sp)
177 lda sp, 16(sp)
178 lda v0, 295(zero) # __sigreturn14
179 call_pal callsys
180
181 Each instruction has a unique encoding, so we simply attempt to match
182 the instruction the PC is pointing to with any of the above instructions.
183 If there is a hit, we know the offset to the start of the designated
184 sequence and can then check whether we really are executing in the
185 signal trampoline. If not, -1 is returned, otherwise the offset from the
186 start of the return sequence is returned. */
948f8e3d 187static const gdb_byte sigtramp_retcode[] =
da8ca43d 188{
cfef91e4
JT
189 0x00, 0x00, 0x1e, 0xa6, /* ldq a0, 0(sp) */
190 0x10, 0x00, 0xde, 0x23, /* lda sp, 16(sp) */
191 0x27, 0x01, 0x1f, 0x20, /* lda v0, 295(zero) */
192 0x83, 0x00, 0x00, 0x00, /* call_pal callsys */
da8ca43d 193};
cfef91e4
JT
194#define RETCODE_NWORDS 4
195#define RETCODE_SIZE (RETCODE_NWORDS * 4)
da8ca43d 196
b0ca8573 197static LONGEST
e17a4113 198alphanbsd_sigtramp_offset (struct gdbarch *gdbarch, CORE_ADDR pc)
da8ca43d 199{
948f8e3d 200 gdb_byte ret[RETCODE_SIZE], w[4];
da8ca43d
JT
201 LONGEST off;
202 int i;
203
948f8e3d 204 if (target_read_memory (pc, w, 4) != 0)
da8ca43d
JT
205 return -1;
206
207 for (i = 0; i < RETCODE_NWORDS; i++)
208 {
cfef91e4 209 if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0)
da8ca43d
JT
210 break;
211 }
212 if (i == RETCODE_NWORDS)
213 return (-1);
214
215 off = i * 4;
216 pc -= off;
217
948f8e3d 218 if (target_read_memory (pc, ret, sizeof (ret)) != 0)
da8ca43d
JT
219 return -1;
220
cfef91e4 221 if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0)
da8ca43d
JT
222 return off;
223
224 return -1;
225}
226
6c72f9f9 227static int
e17a4113 228alphanbsd_pc_in_sigtramp (struct gdbarch *gdbarch,
2c02bd72 229 CORE_ADDR pc, const char *func_name)
6c72f9f9 230{
3d9b49b0 231 return (nbsd_pc_in_sigtramp (pc, func_name)
e17a4113 232 || alphanbsd_sigtramp_offset (gdbarch, pc) >= 0);
6c72f9f9
JT
233}
234
2ca8ae21
JT
235static CORE_ADDR
236alphanbsd_sigcontext_addr (struct frame_info *frame)
237{
238 /* FIXME: This is not correct for all versions of NetBSD/alpha.
239 We will probably need to disassemble the trampoline to figure
240 out which trampoline frame type we have. */
94afd7a6
UW
241 if (!get_next_frame (frame))
242 return 0;
243 return get_frame_base (get_next_frame (frame));
2ca8ae21 244}
b0ca8573 245\f
2ca8ae21 246
da8ca43d
JT
247static void
248alphanbsd_init_abi (struct gdbarch_info info,
249 struct gdbarch *gdbarch)
250{
251 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
252
baa490c4
RH
253 /* Hook into the DWARF CFI frame unwinder. */
254 alpha_dwarf2_init_abi (info, gdbarch);
255
256 /* Hook into the MDEBUG frame unwinder. */
257 alpha_mdebug_init_abi (info, gdbarch);
258
da8ca43d
JT
259 /* NetBSD/alpha does not provide single step support via ptrace(2); we
260 must use software single-stepping. */
261 set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
262
789f3b5f
MK
263 /* NetBSD/alpha has SVR4-style shared libraries. */
264 set_solib_svr4_fetch_link_map_offsets
265 (gdbarch, svr4_lp64_fetch_link_map_offsets);
da8ca43d
JT
266
267 tdep->dynamic_sigtramp_offset = alphanbsd_sigtramp_offset;
f2524b93 268 tdep->pc_in_sigtramp = alphanbsd_pc_in_sigtramp;
2ca8ae21 269 tdep->sigcontext_addr = alphanbsd_sigcontext_addr;
accc6d1f
JT
270
271 tdep->jb_pc = 2;
272 tdep->jb_elt_size = 8;
3beabdb2 273
dff2166e
AA
274 set_gdbarch_iterate_over_regset_sections
275 (gdbarch, alphanbsd_iterate_over_regset_sections);
3beabdb2 276}
3beabdb2
MK
277\f
278
da8ca43d
JT
279void
280_initialize_alphanbsd_tdep (void)
281{
1736a7bd
PA
282 /* Even though NetBSD/alpha used ELF since day one, it used the
283 traditional a.out-style core dump format before NetBSD 1.6, but
284 we don't support those. */
285 gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD,
70f80edf 286 alphanbsd_init_abi);
da8ca43d 287}
This page took 1.286932 seconds and 4 git commands to generate.