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