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