a4dd6e903455a2bf1e1eb2306835fec846e5036f
[deliverable/binutils-gdb.git] / gdb / alphanbsd-tdep.c
1 /* Target-dependent code for NetBSD/alpha.
2
3 Copyright (C) 2002-2014 Free Software Foundation, Inc.
4
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
11 the Free Software Foundation; either version 3 of the License, or
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
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22 #include "defs.h"
23 #include "frame.h"
24 #include "gdbcore.h"
25 #include "osabi.h"
26 #include "regcache.h"
27 #include "regset.h"
28 #include "value.h"
29
30 #include "alpha-tdep.h"
31 #include "alphabsd-tdep.h"
32 #include "nbsd-tdep.h"
33 #include "solib-svr4.h"
34 #include "target.h"
35
36 /* Core file support. */
37
38 /* Even though NetBSD/alpha used ELF since day one, it used the
39 traditional a.out-style core dump format before NetBSD 1.6. */
40
41 /* Sizeof `struct reg' in <machine/reg.h>. */
42 #define ALPHANBSD_SIZEOF_GREGS (32 * 8)
43
44 /* Sizeof `struct fpreg' in <machine/reg.h. */
45 #define ALPHANBSD_SIZEOF_FPREGS ((32 * 8) + 8)
46
47 /* Supply register REGNUM from the buffer specified by FPREGS and LEN
48 in the floating-point register set REGSET to register cache
49 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
50
51 static void
52 alphanbsd_supply_fpregset (const struct regset *regset,
53 struct regcache *regcache,
54 int regnum, const void *fpregs, size_t len)
55 {
56 const gdb_byte *regs = fpregs;
57 int i;
58
59 gdb_assert (len >= ALPHANBSD_SIZEOF_FPREGS);
60
61 for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; i++)
62 {
63 if (regnum == i || regnum == -1)
64 regcache_raw_supply (regcache, i, regs + (i - ALPHA_FP0_REGNUM) * 8);
65 }
66
67 if (regnum == ALPHA_FPCR_REGNUM || regnum == -1)
68 regcache_raw_supply (regcache, ALPHA_FPCR_REGNUM, regs + 32 * 8);
69 }
70
71 /* Supply register REGNUM from the buffer specified by GREGS and LEN
72 in the general-purpose register set REGSET to register cache
73 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
74
75 static void
76 alphanbsd_supply_gregset (const struct regset *regset,
77 struct regcache *regcache,
78 int regnum, const void *gregs, size_t len)
79 {
80 const gdb_byte *regs = gregs;
81 int i;
82
83 gdb_assert (len >= ALPHANBSD_SIZEOF_GREGS);
84
85 for (i = 0; i < ALPHA_ZERO_REGNUM; i++)
86 {
87 if (regnum == i || regnum == -1)
88 regcache_raw_supply (regcache, i, regs + i * 8);
89 }
90
91 if (regnum == ALPHA_PC_REGNUM || regnum == -1)
92 regcache_raw_supply (regcache, ALPHA_PC_REGNUM, regs + 31 * 8);
93 }
94
95 /* Supply register REGNUM from the buffer specified by GREGS and LEN
96 in the general-purpose register set REGSET to register cache
97 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
98
99 static void
100 alphanbsd_aout_supply_gregset (const struct regset *regset,
101 struct regcache *regcache,
102 int regnum, const void *gregs, size_t len)
103 {
104 const gdb_byte *regs = gregs;
105 int i;
106
107 /* Table to map a GDB register number to a trapframe register index. */
108 static const int regmap[] =
109 {
110 0, 1, 2, 3,
111 4, 5, 6, 7,
112 8, 9, 10, 11,
113 12, 13, 14, 15,
114 30, 31, 32, 16,
115 17, 18, 19, 20,
116 21, 22, 23, 24,
117 25, 29, 26
118 };
119
120 gdb_assert (len >= ALPHANBSD_SIZEOF_GREGS);
121
122 for (i = 0; i < ARRAY_SIZE(regmap); i++)
123 {
124 if (regnum == i || regnum == -1)
125 regcache_raw_supply (regcache, i, regs + regmap[i] * 8);
126 }
127
128 if (regnum == ALPHA_PC_REGNUM || regnum == -1)
129 regcache_raw_supply (regcache, ALPHA_PC_REGNUM, regs + 31 * 8);
130
131 if (len >= ALPHANBSD_SIZEOF_GREGS + ALPHANBSD_SIZEOF_FPREGS)
132 {
133 regs += ALPHANBSD_SIZEOF_GREGS;
134 len -= ALPHANBSD_SIZEOF_GREGS;
135 alphanbsd_supply_fpregset (regset, regcache, regnum, regs, len);
136 }
137 }
138
139 /* NetBSD/alpha register sets. */
140
141 static const struct regset alphanbsd_gregset =
142 {
143 NULL,
144 alphanbsd_supply_gregset
145 };
146
147 static const struct regset alphanbsd_fpregset =
148 {
149 NULL,
150 alphanbsd_supply_fpregset
151 };
152
153 static const struct regset alphanbsd_aout_gregset =
154 {
155 NULL,
156 alphanbsd_aout_supply_gregset
157 };
158
159 /* Return the appropriate register set for the core section identified
160 by SECT_NAME and SECT_SIZE. */
161
162 const struct regset *
163 alphanbsd_regset_from_core_section (struct gdbarch *gdbarch,
164 const char *sect_name, size_t sect_size)
165 {
166 if (strcmp (sect_name, ".reg") == 0 && sect_size >= ALPHANBSD_SIZEOF_GREGS)
167 {
168 if (sect_size >= ALPHANBSD_SIZEOF_GREGS + ALPHANBSD_SIZEOF_FPREGS)
169 return &alphanbsd_aout_gregset;
170 else
171 return &alphanbsd_gregset;
172 }
173
174 if (strcmp (sect_name, ".reg2") == 0 && sect_size >= ALPHANBSD_SIZEOF_FPREGS)
175 return &alphanbsd_fpregset;
176
177 return NULL;
178 }
179 \f
180
181 /* Signal trampolines. */
182
183 /* Under NetBSD/alpha, signal handler invocations can be identified by the
184 designated code sequence that is used to return from a signal handler.
185 In particular, the return address of a signal handler points to the
186 following code sequence:
187
188 ldq a0, 0(sp)
189 lda sp, 16(sp)
190 lda v0, 295(zero) # __sigreturn14
191 call_pal callsys
192
193 Each instruction has a unique encoding, so we simply attempt to match
194 the instruction the PC is pointing to with any of the above instructions.
195 If there is a hit, we know the offset to the start of the designated
196 sequence and can then check whether we really are executing in the
197 signal trampoline. If not, -1 is returned, otherwise the offset from the
198 start of the return sequence is returned. */
199 static const gdb_byte sigtramp_retcode[] =
200 {
201 0x00, 0x00, 0x1e, 0xa6, /* ldq a0, 0(sp) */
202 0x10, 0x00, 0xde, 0x23, /* lda sp, 16(sp) */
203 0x27, 0x01, 0x1f, 0x20, /* lda v0, 295(zero) */
204 0x83, 0x00, 0x00, 0x00, /* call_pal callsys */
205 };
206 #define RETCODE_NWORDS 4
207 #define RETCODE_SIZE (RETCODE_NWORDS * 4)
208
209 static LONGEST
210 alphanbsd_sigtramp_offset (struct gdbarch *gdbarch, CORE_ADDR pc)
211 {
212 gdb_byte ret[RETCODE_SIZE], w[4];
213 LONGEST off;
214 int i;
215
216 if (target_read_memory (pc, w, 4) != 0)
217 return -1;
218
219 for (i = 0; i < RETCODE_NWORDS; i++)
220 {
221 if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0)
222 break;
223 }
224 if (i == RETCODE_NWORDS)
225 return (-1);
226
227 off = i * 4;
228 pc -= off;
229
230 if (target_read_memory (pc, ret, sizeof (ret)) != 0)
231 return -1;
232
233 if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0)
234 return off;
235
236 return -1;
237 }
238
239 static int
240 alphanbsd_pc_in_sigtramp (struct gdbarch *gdbarch,
241 CORE_ADDR pc, const char *func_name)
242 {
243 return (nbsd_pc_in_sigtramp (pc, func_name)
244 || alphanbsd_sigtramp_offset (gdbarch, pc) >= 0);
245 }
246
247 static CORE_ADDR
248 alphanbsd_sigcontext_addr (struct frame_info *frame)
249 {
250 /* FIXME: This is not correct for all versions of NetBSD/alpha.
251 We will probably need to disassemble the trampoline to figure
252 out which trampoline frame type we have. */
253 if (!get_next_frame (frame))
254 return 0;
255 return get_frame_base (get_next_frame (frame));
256 }
257 \f
258
259 static void
260 alphanbsd_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
291 static enum gdb_osabi
292 alphanbsd_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. */
302 void _initialize_alphanbsd_tdep (void);
303
304 void
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.035858 seconds and 3 git commands to generate.