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