2003-11-16 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / gdb / mipsnbsd-tdep.c
CommitLineData
45888261 1/* Target-dependent code for MIPS systems running NetBSD.
f4dbdb54 2 Copyright 2002, 2003 Free Software Foundation, Inc.
45888261
JT
3 Contributed by Wasabi Systems, Inc.
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
9 the Free Software Foundation; either version 2 of the License, or
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
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22#include "defs.h"
23#include "gdbcore.h"
24#include "regcache.h"
25#include "target.h"
26#include "value.h"
27#include "osabi.h"
28
3d9b49b0 29#include "nbsd-tdep.h"
45888261
JT
30#include "mipsnbsd-tdep.h"
31
32#include "solib-svr4.h"
33
34/* Conveniently, GDB uses the same register numbering as the
35 ptrace register structure used by NetBSD/mips. */
36
37void
38mipsnbsd_supply_reg (char *regs, int regno)
39{
40 int i;
41
42 for (i = 0; i <= PC_REGNUM; i++)
43 {
44 if (regno == i || regno == -1)
45 {
46 if (CANNOT_FETCH_REGISTER (i))
47 supply_register (i, NULL);
48 else
4246e332 49 supply_register (i, regs + (i * mips_regsize (current_gdbarch)));
45888261
JT
50 }
51 }
52}
53
54void
55mipsnbsd_fill_reg (char *regs, int regno)
56{
57 int i;
58
59 for (i = 0; i <= PC_REGNUM; i++)
60 if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i))
4246e332 61 regcache_collect (i, regs + (i * mips_regsize (current_gdbarch)));
45888261
JT
62}
63
64void
65mipsnbsd_supply_fpreg (char *fpregs, int regno)
66{
67 int i;
68
69 for (i = FP0_REGNUM; i <= FCRIR_REGNUM; i++)
70 {
71 if (regno == i || regno == -1)
72 {
73 if (CANNOT_FETCH_REGISTER (i))
74 supply_register (i, NULL);
75 else
4246e332 76 supply_register (i, fpregs + ((i - FP0_REGNUM) * mips_regsize (current_gdbarch)));
45888261
JT
77 }
78 }
79}
80
81void
82mipsnbsd_fill_fpreg (char *fpregs, int regno)
83{
84 int i;
85
86 for (i = FP0_REGNUM; i <= FCRCS_REGNUM; i++)
87 if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i))
4246e332 88 regcache_collect (i, fpregs + ((i - FP0_REGNUM) * mips_regsize (current_gdbarch)));
45888261
JT
89}
90
91static void
92fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
93 CORE_ADDR ignore)
94{
95 char *regs, *fpregs;
96
97 /* We get everything from one section. */
98 if (which != 0)
99 return;
100
101 regs = core_reg_sect;
102 fpregs = core_reg_sect + SIZEOF_STRUCT_REG;
103
104 /* Integer registers. */
105 mipsnbsd_supply_reg (regs, -1);
106
107 /* Floating point registers. */
f4dbdb54 108 mipsnbsd_supply_fpreg (fpregs, -1);
45888261
JT
109}
110
111static void
112fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
113 CORE_ADDR ignore)
114{
115 switch (which)
116 {
117 case 0: /* Integer registers. */
118 if (core_reg_size != SIZEOF_STRUCT_REG)
119 warning ("Wrong size register set in core file.");
120 else
121 mipsnbsd_supply_reg (core_reg_sect, -1);
122 break;
123
124 case 2: /* Floating point registers. */
125 if (core_reg_size != SIZEOF_STRUCT_FPREG)
126 warning ("Wrong size register set in core file.");
127 else
128 mipsnbsd_supply_fpreg (core_reg_sect, -1);
129 break;
130
131 default:
132 /* Don't know what kind of register request this is; just ignore it. */
133 break;
134 }
135}
136
137static struct core_fns mipsnbsd_core_fns =
138{
139 bfd_target_unknown_flavour, /* core_flavour */
140 default_check_format, /* check_format */
141 default_core_sniffer, /* core_sniffer */
142 fetch_core_registers, /* core_read_registers */
143 NULL /* next */
144};
145
146static struct core_fns mipsnbsd_elfcore_fns =
147{
148 bfd_target_elf_flavour, /* core_flavour */
149 default_check_format, /* check_format */
150 default_core_sniffer, /* core_sniffer */
151 fetch_elfcore_registers, /* core_read_registers */
152 NULL /* next */
153};
154
155/* Under NetBSD/mips, signal handler invocations can be identified by the
156 designated code sequence that is used to return from a signal handler.
157 In particular, the return address of a signal handler points to the
158 following code sequence:
159
160 addu a0, sp, 16
161 li v0, 295 # __sigreturn14
162 syscall
163
164 Each instruction has a unique encoding, so we simply attempt to match
165 the instruction the PC is pointing to with any of the above instructions.
166 If there is a hit, we know the offset to the start of the designated
167 sequence and can then check whether we really are executing in the
168 signal trampoline. If not, -1 is returned, otherwise the offset from the
169 start of the return sequence is returned. */
170
171#define RETCODE_NWORDS 3
172#define RETCODE_SIZE (RETCODE_NWORDS * 4)
173
174static const unsigned char sigtramp_retcode_mipsel[RETCODE_SIZE] =
175{
176 0x10, 0x00, 0xa4, 0x27, /* addu a0, sp, 16 */
177 0x27, 0x01, 0x02, 0x24, /* li v0, 295 */
178 0x0c, 0x00, 0x00, 0x00, /* syscall */
179};
180
181static const unsigned char sigtramp_retcode_mipseb[RETCODE_SIZE] =
182{
183 0x27, 0xa4, 0x00, 0x10, /* addu a0, sp, 16 */
184 0x24, 0x02, 0x01, 0x27, /* li v0, 295 */
185 0x00, 0x00, 0x00, 0x0c, /* syscall */
186};
187
188static LONGEST
189mipsnbsd_sigtramp_offset (CORE_ADDR pc)
190{
191 const char *retcode = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
192 ? sigtramp_retcode_mipseb : sigtramp_retcode_mipsel;
193 unsigned char ret[RETCODE_SIZE], w[4];
194 LONGEST off;
195 int i;
196
197 if (read_memory_nobpt (pc, (char *) w, sizeof (w)) != 0)
198 return -1;
199
200 for (i = 0; i < RETCODE_NWORDS; i++)
201 {
202 if (memcmp (w, retcode + (i * 4), 4) == 0)
203 break;
204 }
205 if (i == RETCODE_NWORDS)
206 return -1;
207
208 off = i * 4;
209 pc -= off;
210
211 if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0)
212 return -1;
213
214 if (memcmp (ret, retcode, RETCODE_SIZE) == 0)
215 return off;
216
217 return -1;
218}
219
220static int
221mipsnbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
222{
3d9b49b0
JT
223 return (nbsd_pc_in_sigtramp (pc, func_name)
224 || mipsnbsd_sigtramp_offset (pc) >= 0);
45888261
JT
225}
226
227/* Figure out where the longjmp will land. We expect that we have
228 just entered longjmp and haven't yet setup the stack frame, so
229 the args are still in the argument regs. A0_REGNUM points at the
230 jmp_buf structure from which we extract the PC that we will land
231 at. The PC is copied into *pc. This routine returns true on
232 success. */
233
234#define NBSD_MIPS_JB_PC (2 * 4)
4246e332 235#define NBSD_MIPS_JB_ELEMENT_SIZE mips_regsize (current_gdbarch)
45888261
JT
236#define NBSD_MIPS_JB_OFFSET (NBSD_MIPS_JB_PC * \
237 NBSD_MIPS_JB_ELEMENT_SIZE)
238
239static int
240mipsnbsd_get_longjmp_target (CORE_ADDR *pc)
241{
242 CORE_ADDR jb_addr;
243 char *buf;
244
245 buf = alloca (NBSD_MIPS_JB_ELEMENT_SIZE);
246
247 jb_addr = read_register (A0_REGNUM);
248
249 if (target_read_memory (jb_addr + NBSD_MIPS_JB_OFFSET, buf,
250 NBSD_MIPS_JB_ELEMENT_SIZE))
251 return 0;
252
7c0b4a20 253 *pc = extract_unsigned_integer (buf, NBSD_MIPS_JB_ELEMENT_SIZE);
45888261
JT
254
255 return 1;
256}
257
258static int
259mipsnbsd_cannot_fetch_register (int regno)
260{
a094c6fb 261 return (regno == ZERO_REGNUM
45888261
JT
262 || regno == FCRIR_REGNUM);
263}
264
265static int
266mipsnbsd_cannot_store_register (int regno)
267{
a094c6fb 268 return (regno == ZERO_REGNUM
45888261
JT
269 || regno == FCRIR_REGNUM);
270}
271
272/* NetBSD/mips uses a slightly different link_map structure from the
273 other NetBSD platforms. */
274static struct link_map_offsets *
275mipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets (void)
276{
277 static struct link_map_offsets lmo;
278 static struct link_map_offsets *lmp = NULL;
279
280 if (lmp == NULL)
281 {
282 lmp = &lmo;
283
284 lmo.r_debug_size = 16;
285
286 lmo.r_map_offset = 4;
287 lmo.r_map_size = 4;
288
289 lmo.link_map_size = 24;
290
291 lmo.l_addr_offset = 0;
292 lmo.l_addr_size = 4;
293
294 lmo.l_name_offset = 8;
295 lmo.l_name_size = 4;
296
297 lmo.l_next_offset = 16;
298 lmo.l_next_size = 4;
299
300 lmo.l_prev_offset = 20;
301 lmo.l_prev_size = 4;
302 }
303
304 return lmp;
305}
306
307static struct link_map_offsets *
308mipsnbsd_lp64_solib_svr4_fetch_link_map_offsets (void)
309{
310 static struct link_map_offsets lmo;
311 static struct link_map_offsets *lmp = NULL;
312
313 if (lmp == NULL)
314 {
315 lmp = &lmo;
316
317 lmo.r_debug_size = 32;
318
319 lmo.r_map_offset = 8;
320 lmo.r_map_size = 8;
321
322 lmo.link_map_size = 48;
323
324 lmo.l_addr_offset = 0;
325 lmo.l_addr_size = 8;
326
327 lmo.l_name_offset = 16;
328 lmo.l_name_size = 8;
329
330 lmo.l_next_offset = 32;
331 lmo.l_next_size = 8;
332
333 lmo.l_prev_offset = 40;
334 lmo.l_prev_size = 8;
335 }
336
337 return lmp;
338}
339
340static void
341mipsnbsd_init_abi (struct gdbarch_info info,
342 struct gdbarch *gdbarch)
343{
344 set_gdbarch_pc_in_sigtramp (gdbarch, mipsnbsd_pc_in_sigtramp);
345
346 set_gdbarch_get_longjmp_target (gdbarch, mipsnbsd_get_longjmp_target);
347
348 set_gdbarch_cannot_fetch_register (gdbarch, mipsnbsd_cannot_fetch_register);
349 set_gdbarch_cannot_store_register (gdbarch, mipsnbsd_cannot_store_register);
350
351 set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
352
353 set_solib_svr4_fetch_link_map_offsets (gdbarch,
354 gdbarch_ptr_bit (gdbarch) == 32 ?
355 mipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets :
356 mipsnbsd_lp64_solib_svr4_fetch_link_map_offsets);
357}
358
359void
360_initialize_mipsnbsd_tdep (void)
361{
05816f70 362 gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_NETBSD_ELF,
45888261
JT
363 mipsnbsd_init_abi);
364
365 add_core_fns (&mipsnbsd_core_fns);
366 add_core_fns (&mipsnbsd_elfcore_fns);
367}
This page took 0.284812 seconds and 4 git commands to generate.