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