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